Merge "Drive-by fix for wtfIfInLock + two violations" into sc-dev
diff --git a/StubLibraries.bp b/StubLibraries.bp
index b995f95..e6f50b7 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -403,16 +403,6 @@
}
java_defaults {
- name: "android_defaults_stubs_current",
- sdk_version: "none",
- system_modules: "none",
- java_version: "1.8",
- compile_dex: true,
- defaults_visibility: ["//visibility:private"],
- visibility: ["//visibility:public"],
-}
-
-java_defaults {
name: "android_stubs_dists_default",
dist: {
targets: [
@@ -431,7 +421,7 @@
"android-non-updatable.stubs",
"private-stub-annotations-jar",
],
- defaults: ["android_defaults_stubs_current"],
+ defaults: ["android.jar_defaults"],
}
java_library_static {
@@ -441,7 +431,7 @@
"private-stub-annotations-jar",
],
defaults: [
- "android_defaults_stubs_current",
+ "android.jar_defaults",
"android_stubs_dists_default",
],
dist: {
@@ -469,7 +459,7 @@
"private-stub-annotations-jar",
],
defaults: [
- "android_defaults_stubs_current",
+ "android.jar_defaults",
"android_stubs_dists_default",
],
dist: {
@@ -480,7 +470,7 @@
java_library_static {
name: "android_module_lib_stubs_current",
defaults: [
- "android_defaults_stubs_current",
+ "android.jar_defaults",
"android_stubs_dists_default",
],
static_libs: [
diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp
index 57ee1ec..566a18f 100644
--- a/apex/appsearch/service/Android.bp
+++ b/apex/appsearch/service/Android.bp
@@ -28,6 +28,7 @@
"framework",
"framework-appsearch",
"services.core",
+ "services.usage",
],
static_libs: [
"icing-java-proto-lite",
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index ec81ed2..3f6e8a5 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.appsearch;
import static android.app.appsearch.AppSearchResult.throwableToFailedResult;
+import static android.os.Process.INVALID_UID;
import static android.os.UserHandle.USER_NULL;
import android.annotation.ElapsedRealtimeLong;
@@ -40,7 +41,9 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageStats;
import android.os.Binder;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
@@ -51,7 +54,6 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalServices;
@@ -60,6 +62,8 @@
import com.android.server.appsearch.external.localstorage.stats.CallStats;
import com.android.server.appsearch.stats.LoggerInstanceManager;
import com.android.server.appsearch.stats.PlatformLogger;
+import com.android.server.usage.StorageStatsManagerInternal;
+import com.android.server.usage.StorageStatsManagerInternal.StorageStatsAugmenter;
import com.google.android.icing.proto.PersistType;
@@ -82,6 +86,7 @@
public class AppSearchManagerService extends SystemService {
private static final String TAG = "AppSearchManagerService";
private final Context mContext;
+ private PackageManager mPackageManager;
private PackageManagerInternal mPackageManagerInternal;
private ImplInstanceManager mImplInstanceManager;
private UserManager mUserManager;
@@ -109,17 +114,31 @@
@Override
public void onStart() {
publishBinderService(Context.APP_SEARCH_SERVICE, new Stub());
+ mPackageManager = getContext().getPackageManager();
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mImplInstanceManager = ImplInstanceManager.getInstance(mContext);
mUserManager = mContext.getSystemService(UserManager.class);
mLoggerInstanceManager = LoggerInstanceManager.getInstance();
registerReceivers();
+ LocalServices.getService(StorageStatsManagerInternal.class)
+ .registerStorageStatsAugmenter(new AppSearchStorageStatsAugmenter(), TAG);
}
private void registerReceivers() {
mContext.registerReceiverAsUser(new UserActionReceiver(), UserHandle.ALL,
new IntentFilter(Intent.ACTION_USER_REMOVED), /*broadcastPermission=*/ null,
/*scheduler=*/ null);
+
+ //TODO(b/145759910) Add a direct callback when user clears the data instead of relying on
+ // broadcasts
+ IntentFilter packageChangedFilter = new IntentFilter();
+ packageChangedFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+ packageChangedFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
+ packageChangedFilter.addDataScheme("package");
+ packageChangedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiverAsUser(new PackageChangedReceiver(), UserHandle.ALL,
+ packageChangedFilter, /*broadcastPermission=*/ null,
+ /*scheduler=*/ null);
}
private class UserActionReceiver extends BroadcastReceiver {
@@ -127,15 +146,15 @@
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
switch (intent.getAction()) {
case Intent.ACTION_USER_REMOVED:
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
if (userId == USER_NULL) {
- Slog.e(TAG, "userId is missing in the intent: " + intent);
+ Log.e(TAG, "userId is missing in the intent: " + intent);
return;
}
handleUserRemoved(userId);
break;
default:
- Slog.e(TAG, "Received unknown intent: " + intent);
+ Log.e(TAG, "Received unknown intent: " + intent);
}
}
}
@@ -155,9 +174,52 @@
try {
mImplInstanceManager.removeAppSearchImplForUser(userId);
mLoggerInstanceManager.removePlatformLoggerForUser(userId);
- Slog.i(TAG, "Removed AppSearchImpl instance for user: " + userId);
+ Log.i(TAG, "Removed AppSearchImpl instance for user: " + userId);
} catch (Throwable t) {
- Slog.e(TAG, "Unable to remove data for user: " + userId, t);
+ Log.e(TAG, "Unable to remove data for user: " + userId, t);
+ }
+ }
+
+ private class PackageChangedReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(@NonNull Context context, @NonNull Intent intent) {
+ switch (intent.getAction()) {
+ case Intent.ACTION_PACKAGE_FULLY_REMOVED:
+ case Intent.ACTION_PACKAGE_DATA_CLEARED:
+ String packageName = intent.getData().getSchemeSpecificPart();
+ if (packageName == null) {
+ Log.e(TAG, "Package name is missing in the intent: " + intent);
+ return;
+ }
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, INVALID_UID);
+ if (uid == INVALID_UID) {
+ Log.e(TAG, "uid is missing in the intent: " + intent);
+ return;
+ }
+ handlePackageRemoved(packageName, uid);
+ break;
+ default:
+ Log.e(TAG, "Received unknown intent: " + intent);
+ }
+ }
+ }
+
+ private void handlePackageRemoved(String packageName, int uid) {
+ int userId = UserHandle.getUserId(uid);
+ try {
+ if (isUserLocked(userId)) {
+ //TODO(b/186151459) clear the uninstalled package data when user is unlocked.
+ return;
+ }
+ if (ImplInstanceManager.getAppSearchDir(userId).exists()) {
+ // Only clear the package's data if AppSearch exists for this user.
+ AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
+ userId);
+ //TODO(b/145759910) clear visibility setting for package.
+ impl.clearPackageData(packageName);
+ }
+ } catch (Throwable t) {
+ Log.e(TAG, "Unable to remove data for package: " + packageName, t);
}
}
@@ -168,6 +230,24 @@
}
}
+ private void verifyUserUnlocked(int callingUserId) {
+ if (isUserLocked(callingUserId)) {
+ throw new IllegalStateException("User " + callingUserId + " is locked or not running.");
+ }
+ }
+
+ private boolean isUserLocked(int callingUserId) {
+ synchronized (mUnlockedUserIdsLocked) {
+ // First, check the local copy.
+ if (mUnlockedUserIdsLocked.contains(callingUserId)) {
+ return false;
+ }
+ // If the local copy says the user is locked, check with UM for the actual state,
+ // since the user might just have been unlocked.
+ return !mUserManager.isUserUnlockingOrUnlocked(UserHandle.of(callingUserId));
+ }
+ }
+
private class Stub extends IAppSearchManager.Stub {
@Override
public void setSchema(
@@ -769,25 +849,10 @@
});
}
- private void verifyUserUnlocked(int callingUserId) {
- synchronized (mUnlockedUserIdsLocked) {
- // First, check the local copy.
- if (mUnlockedUserIdsLocked.contains(callingUserId)) {
- return;
- }
- // If the local copy says the user is locked, check with UM for the actual state,
- // since the user might just have been unlocked.
- if (!mUserManager.isUserUnlockingOrUnlocked(UserHandle.of(callingUserId))) {
- throw new IllegalStateException(
- "User " + callingUserId + " is locked or not running.");
- }
- }
- }
-
private void verifyCallingPackage(int callingUid, @NonNull String callingPackage) {
Objects.requireNonNull(callingPackage);
if (mPackageManagerInternal.getPackageUid(
- callingPackage, /*flags=*/ 0, UserHandle.getUserId(callingUid))
+ callingPackage, /*flags=*/ 0, UserHandle.getUserId(callingUid))
!= callingUid) {
throw new SecurityException(
"Specified calling package ["
@@ -859,4 +924,52 @@
/*name=*/ null,
/*callerPackage=*/ null);
}
+
+ // TODO(b/179160886): Cache the previous storage stats.
+ private class AppSearchStorageStatsAugmenter implements StorageStatsAugmenter {
+ @Override
+ public void augmentStatsForPackage(
+ @NonNull PackageStats stats,
+ @NonNull String packageName,
+ @UserIdInt int userId,
+ boolean callerHasStatsPermission) {
+ Objects.requireNonNull(stats);
+ Objects.requireNonNull(packageName);
+ try {
+ verifyUserUnlocked(userId);
+ AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
+ userId);
+ stats.dataSize += impl.getStorageInfoForPackage(packageName).getSizeBytes();
+ } catch (Throwable t) {
+ Log.e(
+ TAG,
+ "Unable to augment storage stats for userId "
+ + userId
+ + " packageName "
+ + packageName,
+ t);
+ }
+ }
+
+ @Override
+ public void augmentStatsForUid(
+ @NonNull PackageStats stats, int uid, boolean callerHasStatsPermission) {
+ Objects.requireNonNull(stats);
+ int userId = UserHandle.getUserId(uid);
+ try {
+ verifyUserUnlocked(userId);
+ String[] packagesForUid = mPackageManager.getPackagesForUid(uid);
+ if (packagesForUid == null) {
+ return;
+ }
+ AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
+ userId);
+ for (String packageName : packagesForUid) {
+ stats.dataSize += impl.getStorageInfoForPackage(packageName).getSizeBytes();
+ }
+ } catch (Throwable t) {
+ Log.e(TAG, "Unable to augment storage stats for uid " + uid, t);
+ }
+ }
+ }
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
index af39b79..45023f9 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
@@ -73,6 +73,15 @@
}
/**
+ * Returns AppSearch directory in the credential encrypted system directory for the given user.
+ *
+ * <p>This folder should only be accessed after unlock.
+ */
+ public static File getAppSearchDir(@UserIdInt int userId) {
+ return new File(Environment.getDataSystemCeDirectory(userId), APP_SEARCH_DIR);
+ }
+
+ /**
* Gets an instance of AppSearchImpl for the given user, or creates one if none exists.
*
* <p>If no AppSearchImpl instance exists for the unlocked user, Icing will be initialized and
@@ -139,15 +148,10 @@
private AppSearchImpl createImpl(@NonNull Context context, @UserIdInt int userId)
throws AppSearchException {
- File appSearchDir = getAppSearchDir(context, userId);
+ File appSearchDir = getAppSearchDir(userId);
return AppSearchImpl.create(appSearchDir, context, userId, mGlobalQuerierPackage);
}
- private static File getAppSearchDir(@NonNull Context context, @UserIdInt int userId) {
- // See com.android.internal.app.ChooserActivity::getPinnedSharedPrefs
- return new File(Environment.getDataSystemCeDirectory(userId), APP_SEARCH_DIR);
- }
-
/**
* Returns the global querier package if it's a system package. Otherwise, empty string.
*
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
index 3bc7b30..9ffef9c 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
@@ -66,6 +66,23 @@
*/
public static final int BATTERY_SAVER_POLICY_INDEX = 3;
+ /**
+ * Reason to use for inexact alarms.
+ */
+ static final int EXACT_ALLOW_REASON_NOT_APPLICABLE = -1;
+ /**
+ * Caller had SCHEDULE_EXACT_ALARM permission.
+ */
+ static final int EXACT_ALLOW_REASON_PERMISSION = 0;
+ /**
+ * Caller was in the power allow-list.
+ */
+ static final int EXACT_ALLOW_REASON_ALLOW_LIST = 1;
+ /**
+ * Change wasn't enable for the caller due to compat reasons.
+ */
+ static final int EXACT_ALLOW_REASON_COMPAT = 2;
+
public final int type;
/**
* The original trigger time supplied by the caller. This can be in the elapsed or rtc time base
@@ -92,13 +109,15 @@
/** The ultimate delivery time to be used for this alarm */
private long mWhenElapsed;
private long mMaxWhenElapsed;
+ public int mExactAllowReason;
public AlarmManagerService.PriorityClass priorityClass;
/** Broadcast options to use when delivering this alarm */
public Bundle mIdleOptions;
Alarm(int type, long when, long requestedWhenElapsed, long windowLength, long interval,
PendingIntent op, IAlarmListener rec, String listenerTag, WorkSource ws, int flags,
- AlarmManager.AlarmClockInfo info, int uid, String pkgName, Bundle idleOptions) {
+ AlarmManager.AlarmClockInfo info, int uid, String pkgName, Bundle idleOptions,
+ int exactAllowReason) {
this.type = type;
origWhen = when;
wakeup = type == AlarmManager.ELAPSED_REALTIME_WAKEUP
@@ -119,6 +138,7 @@
this.uid = uid;
packageName = pkgName;
mIdleOptions = idleOptions;
+ mExactAllowReason = exactAllowReason;
sourcePackage = (operation != null) ? operation.getCreatorPackage() : packageName;
creatorUid = (operation != null) ? operation.getCreatorUid() : this.uid;
}
@@ -216,7 +236,6 @@
sb.append(type);
sb.append(" origWhen ");
sb.append(origWhen);
- sb.append(" ");
sb.append(" whenElapsed ");
sb.append(getWhenElapsed());
sb.append(" ");
@@ -240,6 +259,21 @@
}
}
+ private static String exactReasonToString(int reason) {
+ switch (reason) {
+ case EXACT_ALLOW_REASON_ALLOW_LIST:
+ return "allow-listed";
+ case EXACT_ALLOW_REASON_COMPAT:
+ return "compat";
+ case EXACT_ALLOW_REASON_PERMISSION:
+ return "permission";
+ case EXACT_ALLOW_REASON_NOT_APPLICABLE:
+ return "N/A";
+ default:
+ return "--unknown--";
+ }
+ }
+
public static String typeToString(int type) {
switch (type) {
case RTC:
@@ -270,6 +304,10 @@
}
ipw.print(" window=");
TimeUtils.formatDuration(windowLength, ipw);
+ if (mExactAllowReason != EXACT_ALLOW_REASON_NOT_APPLICABLE) {
+ ipw.print(" exactAllowReason=");
+ ipw.print(exactReasonToString(mExactAllowReason));
+ }
ipw.print(" repeatInterval=");
ipw.print(repeatInterval);
ipw.print(" count=");
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index e63a7c4..5554ad2 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -38,6 +38,10 @@
import static com.android.server.alarm.Alarm.APP_STANDBY_POLICY_INDEX;
import static com.android.server.alarm.Alarm.BATTERY_SAVER_POLICY_INDEX;
import static com.android.server.alarm.Alarm.DEVICE_IDLE_POLICY_INDEX;
+import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_ALLOW_LIST;
+import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_COMPAT;
+import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_NOT_APPLICABLE;
+import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION;
import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX;
import android.Manifest;
@@ -223,6 +227,7 @@
private final Injector mInjector;
int mBroadcastRefCount = 0;
+ MetricsHelper mMetricsHelper;
PowerManager.WakeLock mWakeLock;
SparseIntArray mAlarmsPerUid = new SparseIntArray();
ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>();
@@ -1221,7 +1226,7 @@
setImplLocked(alarm.type, alarm.origWhen + delta, nextElapsed,
nextMaxElapsed - nextElapsed, alarm.repeatInterval, alarm.operation, null,
null, alarm.flags, alarm.workSource, alarm.alarmClock, alarm.uid,
- alarm.packageName, null);
+ alarm.packageName, null, EXACT_ALLOW_REASON_NOT_APPLICABLE);
// Kernel alarms will be rescheduled as needed in setImplLocked
}
}
@@ -1442,6 +1447,7 @@
@Override
public void onStart() {
mInjector.init();
+ mMetricsHelper = new MetricsHelper(getContext());
mListenerDeathRecipient = new IBinder.DeathRecipient() {
@Override
@@ -1584,6 +1590,7 @@
});
} catch (RemoteException e) {
}
+ mMetricsHelper.registerPuller(mAlarmStore);
mLocalDeviceIdleController =
LocalServices.getService(DeviceIdleInternal.class);
@@ -1691,7 +1698,7 @@
void setImpl(int type, long triggerAtTime, long windowLength, long interval,
PendingIntent operation, IAlarmListener directReceiver, String listenerTag,
int flags, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock,
- int callingUid, String callingPackage, Bundle idleOptions) {
+ int callingUid, String callingPackage, Bundle idleOptions, int exactAllowReason) {
if ((operation == null && directReceiver == null)
|| (operation != null && directReceiver != null)) {
Slog.w(TAG, "Alarms must either supply a PendingIntent or an AlarmReceiver");
@@ -1788,7 +1795,7 @@
}
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, interval, operation,
directReceiver, listenerTag, flags, workSource, alarmClock, callingUid,
- callingPackage, idleOptions);
+ callingPackage, idleOptions, exactAllowReason);
}
}
@@ -1796,10 +1803,10 @@
long interval, PendingIntent operation, IAlarmListener directReceiver,
String listenerTag, int flags, WorkSource workSource,
AlarmManager.AlarmClockInfo alarmClock, int callingUid, String callingPackage,
- Bundle idleOptions) {
+ Bundle idleOptions, int exactAllowReason) {
final Alarm a = new Alarm(type, when, whenElapsed, windowLength, interval,
operation, directReceiver, listenerTag, workSource, flags, alarmClock,
- callingUid, callingPackage, idleOptions);
+ callingUid, callingPackage, idleOptions, exactAllowReason);
if (mActivityManagerInternal.isAppStartModeDisabled(callingUid, callingPackage)) {
Slog.w(TAG, "Not setting alarm from " + callingUid + ":" + a
+ " -- package not allowed to start");
@@ -1808,6 +1815,7 @@
removeLocked(operation, directReceiver);
incrementAlarmCount(a.uid);
setImplLocked(a);
+ MetricsHelper.pushAlarmScheduled(a);
}
/**
@@ -2220,6 +2228,8 @@
// Make sure the caller is allowed to use the requested kind of alarm, and also
// decide what quota and broadcast options to use.
+ boolean allowListed = false; // For logging the reason.
+ boolean changeDisabled = false; // For logging the reason.
Bundle idleOptions = null;
if ((flags & FLAG_PRIORITIZE) != 0) {
getContext().enforcePermission(
@@ -2236,6 +2246,7 @@
lowerQuota = !exact;
idleOptions = exact ? mOptsWithFgs.toBundle() : mOptsWithoutFgs.toBundle();
} else {
+ changeDisabled = true;
needsPermission = false;
lowerQuota = allowWhileIdle;
idleOptions = allowWhileIdle ? mOptsWithFgs.toBundle() : null;
@@ -2250,6 +2261,8 @@
} else {
Slog.wtf(TAG, errorMessage);
}
+ } else {
+ allowListed = true;
}
// If the app is on the full system power allow-list (not except-idle), or we're
// in a soft failure mode, we still allow the alarms.
@@ -2263,15 +2276,25 @@
flags |= FLAG_ALLOW_WHILE_IDLE_COMPAT;
}
}
-
- // If this is an exact time alarm, then it can't be batched with other alarms.
+ final int exactAllowReason;
if (exact) {
+ // If this is an exact time alarm, then it can't be batched with other alarms.
flags |= AlarmManager.FLAG_STANDALONE;
+
+ if (changeDisabled) {
+ exactAllowReason = EXACT_ALLOW_REASON_COMPAT;
+ } else if (allowListed) {
+ exactAllowReason = EXACT_ALLOW_REASON_ALLOW_LIST;
+ } else {
+ exactAllowReason = EXACT_ALLOW_REASON_PERMISSION;
+ }
+ } else {
+ exactAllowReason = EXACT_ALLOW_REASON_NOT_APPLICABLE;
}
setImpl(type, triggerAtTime, windowLength, interval, operation, directReceiver,
listenerTag, flags, workSource, alarmClock, callingUid, callingPackage,
- idleOptions);
+ idleOptions, exactAllowReason);
}
@Override
@@ -3501,8 +3524,8 @@
private static native int setKernelTimezone(long nativeData, int minuteswest);
private static native long getNextAlarm(long nativeData, int type);
- boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) {
- boolean hasWakeup = false;
+ int triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) {
+ int wakeUps = 0;
final ArrayList<Alarm> pendingAlarms = mAlarmStore.removePendingAlarms(nowELAPSED);
for (final Alarm alarm : pendingAlarms) {
if (isBackgroundRestricted(alarm)) {
@@ -3559,11 +3582,11 @@
setImplLocked(alarm.type, alarm.origWhen + delta, nextElapsed,
nextMaxElapsed - nextElapsed, alarm.repeatInterval, alarm.operation, null,
null, alarm.flags, alarm.workSource, alarm.alarmClock, alarm.uid,
- alarm.packageName, null);
+ alarm.packageName, null, EXACT_ALLOW_REASON_NOT_APPLICABLE);
}
if (alarm.wakeup) {
- hasWakeup = true;
+ wakeUps++;
}
// We removed an alarm clock. Let the caller recompute the next alarm clock.
@@ -3584,7 +3607,7 @@
}
}
- return hasWakeup;
+ return wakeUps;
}
long currentNonWakeupFuzzLocked(long nowELAPSED) {
@@ -3843,8 +3866,8 @@
}
mLastTrigger = nowELAPSED;
- boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED);
- if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
+ final int wakeUps = triggerAlarmsLocked(triggerList, nowELAPSED);
+ if (wakeUps == 0 && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
// if there are no wakeup alarms and the screen is off, we can
// delay what we have so far until the future.
if (mPendingNonWakeupAlarms.size() == 0) {
@@ -3896,6 +3919,7 @@
reorderAlarmsBasedOnStandbyBuckets(triggerPackages);
rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
+ MetricsHelper.pushAlarmBatchDelivered(triggerList.size(), wakeUps);
}
}
@@ -4126,7 +4150,7 @@
setImpl(ELAPSED_REALTIME, mInjector.getElapsedRealtime() + tickEventDelay, 0,
0, null, mTimeTickTrigger, TIME_TICK_TAG, flags, workSource, null,
- Process.myUid(), "android", null);
+ Process.myUid(), "android", null, EXACT_ALLOW_REASON_ALLOW_LIST);
// Finally, remember when we set the tick alarm
synchronized (mLock) {
@@ -4146,7 +4170,7 @@
final WorkSource workSource = null; // Let system take blame for date change events.
setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, null, null,
AlarmManager.FLAG_STANDALONE, workSource, null,
- Process.myUid(), "android", null);
+ Process.myUid(), "android", null, EXACT_ALLOW_REASON_ALLOW_LIST);
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
index e684b84..0172748 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
@@ -139,6 +139,11 @@
String getName();
/**
+ * Returns the number of alarms that satisfy the given condition.
+ */
+ int getCount(Predicate<Alarm> condition);
+
+ /**
* A functional interface used to update the alarm. Used to describe the update in
* {@link #updateAlarmDeliveries(AlarmDeliveryCalculator)}
*/
@@ -153,4 +158,3 @@
boolean updateAlarmDelivery(Alarm a);
}
}
-
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
index cb528ba..1a4efb8 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
@@ -17,7 +17,6 @@
package com.android.server.alarm;
import static com.android.server.alarm.AlarmManagerService.DEBUG_BATCH;
-import static com.android.server.alarm.AlarmManagerService.TAG;
import static com.android.server.alarm.AlarmManagerService.clampPositive;
import static com.android.server.alarm.AlarmManagerService.dumpAlarmList;
import static com.android.server.alarm.AlarmManagerService.isTimeTickAlarm;
@@ -50,10 +49,12 @@
interface Stats {
int REBATCH_ALL_ALARMS = 0;
+ int GET_COUNT = 1;
}
final StatLogger mStatLogger = new StatLogger(TAG + " stats", new String[]{
"REBATCH_ALL_ALARMS",
+ "GET_COUNT",
});
private static final Comparator<Batch> sBatchOrder = Comparator.comparingLong(b -> b.mStart);
@@ -219,6 +220,22 @@
return TAG;
}
+ @Override
+ public int getCount(Predicate<Alarm> condition) {
+ long start = mStatLogger.getTime();
+
+ int count = 0;
+ for (Batch b : mAlarmBatches) {
+ for (int i = 0; i < b.size(); i++) {
+ if (condition.test(b.get(i))) {
+ count++;
+ }
+ }
+ }
+ mStatLogger.logDurationStat(Stats.GET_COUNT, start);
+ return count;
+ }
+
private void insertAndBatchAlarm(Alarm alarm) {
final int whichBatch = ((alarm.flags & AlarmManager.FLAG_STANDALONE) != 0) ? -1
: attemptCoalesce(alarm.getWhenElapsed(), alarm.getMaxWhenElapsed());
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java
index 9b1b066..2e12e2f 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java
@@ -47,11 +47,13 @@
interface Stats {
int GET_NEXT_DELIVERY_TIME = 0;
int GET_NEXT_WAKEUP_DELIVERY_TIME = 1;
+ int GET_COUNT = 2;
}
final StatLogger mStatLogger = new StatLogger(TAG + " stats", new String[]{
"GET_NEXT_DELIVERY_TIME",
"GET_NEXT_WAKEUP_DELIVERY_TIME",
+ "GET_COUNT",
});
// Decreasing time order because it is more efficient to remove from the tail of an array list.
@@ -221,4 +223,18 @@
public String getName() {
return TAG;
}
+
+ @Override
+ public int getCount(Predicate<Alarm> condition) {
+ long start = mStatLogger.getTime();
+
+ int count = 0;
+ for (final Alarm a : mAlarms) {
+ if (condition.test(a)) {
+ count++;
+ }
+ }
+ mStatLogger.logDurationStat(Stats.GET_COUNT, start);
+ return count;
+ }
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
new file mode 100644
index 0000000..a8cf7b2
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.alarm;
+
+import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__ALLOW_LIST;
+import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__CHANGE_DISABLED;
+import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__NOT_APPLICABLE;
+import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PERMISSION;
+import static com.android.server.alarm.AlarmManagerService.INDEFINITE_DELAY;
+
+import android.app.AlarmManager;
+import android.app.StatsManager;
+import android.content.Context;
+import android.os.SystemClock;
+
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.FrameworkStatsLog;
+
+/**
+ * A helper class to write logs to statsd.
+ */
+class MetricsHelper {
+ private Context mContext;
+
+ MetricsHelper(Context context) {
+ mContext = context;
+ }
+
+ void registerPuller(AlarmStore alarmStore) {
+ final StatsManager statsManager = mContext.getSystemService(StatsManager.class);
+ statsManager.setPullAtomCallback(FrameworkStatsLog.PENDING_ALARM_INFO, null,
+ BackgroundThread.getExecutor(), (atomTag, data) -> {
+ if (atomTag != FrameworkStatsLog.PENDING_ALARM_INFO) {
+ throw new UnsupportedOperationException("Unknown tag" + atomTag);
+ }
+ final long now = SystemClock.elapsedRealtime();
+ data.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ alarmStore.size(),
+ alarmStore.getCount(a -> a.windowLength == 0),
+ alarmStore.getCount(a -> a.wakeup),
+ alarmStore.getCount(
+ a -> (a.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0),
+ alarmStore.getCount(a -> (a.flags & AlarmManager.FLAG_PRIORITIZE) != 0),
+ alarmStore.getCount(a -> (a.operation != null
+ && a.operation.isForegroundService())),
+ alarmStore.getCount(
+ a -> (a.operation != null && a.operation.isActivity())),
+ alarmStore.getCount(
+ a -> (a.operation != null && a.operation.isService())),
+ alarmStore.getCount(a -> (a.listener != null)),
+ alarmStore.getCount(
+ a -> (a.getRequestedElapsed() > now + INDEFINITE_DELAY)),
+ alarmStore.getCount(a -> (a.repeatInterval != 0)),
+ alarmStore.getCount(a -> (a.alarmClock != null))
+ ));
+ return StatsManager.PULL_SUCCESS;
+ });
+ }
+
+ private static int reasonToStatsReason(int reasonCode) {
+ switch (reasonCode) {
+ case Alarm.EXACT_ALLOW_REASON_ALLOW_LIST:
+ return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__ALLOW_LIST;
+ case Alarm.EXACT_ALLOW_REASON_PERMISSION:
+ return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PERMISSION;
+ case Alarm.EXACT_ALLOW_REASON_COMPAT:
+ return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__CHANGE_DISABLED;
+ default:
+ return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__NOT_APPLICABLE;
+ }
+ }
+
+ static void pushAlarmScheduled(Alarm a) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.ALARM_SCHEDULED,
+ a.uid,
+ a.windowLength == 0,
+ a.wakeup,
+ (a.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0,
+ a.alarmClock != null,
+ a.repeatInterval != 0,
+ reasonToStatsReason(a.mExactAllowReason));
+ }
+
+ static void pushAlarmBatchDelivered(int numAlarms, int wakeups) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.ALARM_BATCH_DELIVERED,
+ numAlarms,
+ wakeups);
+ }
+}
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 7020f18..1bf732b 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -41,7 +41,10 @@
installable: true,
sdk_version: "module_current",
- libs: ["framework-annotations-lib"],
+ libs: [
+ "androidx.annotation_annotation",
+ "framework-annotations-lib",
+ ],
static_libs: [
"exoplayer2-extractor",
"mediatranscoding_aidl_interface-java",
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index cff422d..8cc3bc0 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -28,6 +28,10 @@
import android.util.Pair;
import android.util.SparseArray;
+import androidx.annotation.RequiresApi;
+
+import com.android.modules.utils.build.SdkLevel;
+
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException;
@@ -1068,7 +1072,7 @@
private boolean mReleased;
// MediaMetrics fields.
- @NonNull private LogSessionId mLogSessionId = LogSessionId.LOG_SESSION_ID_NONE;
+ @Nullable private LogSessionId mLogSessionId;
private final boolean mCreatedByName;
private final SparseArray<Format> mTrackFormats;
private String mLastObservedExceptionName;
@@ -1331,7 +1335,7 @@
MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH));
nativeSubmitMetrics(
- // TODO: mLogSessionId,
+ SdkLevel.isAtLeastS() ? getLogSessionIdStringV31() : "",
mParserName,
mCreatedByName,
String.join(MEDIAMETRICS_ELEMENT_SEPARATOR, mParserNamesPool),
@@ -1345,13 +1349,15 @@
videoHeight);
}
- public void setLogSessionId(@NonNull LogSessionId sessionId) {
- this.mLogSessionId = Objects.requireNonNull(sessionId);
+ @RequiresApi(31)
+ public void setLogSessionId(@NonNull LogSessionId logSessionId) {
+ this.mLogSessionId = Objects.requireNonNull(logSessionId);
}
+ @RequiresApi(31)
@NonNull
public LogSessionId getLogSessionId() {
- return mLogSessionId;
+ return mLogSessionId != null ? mLogSessionId : LogSessionId.LOG_SESSION_ID_NONE;
}
// Private methods.
@@ -1548,6 +1554,11 @@
return (String) mParserParameters.getOrDefault(name, defaultValue);
}
+ @RequiresApi(31)
+ private String getLogSessionIdStringV31() {
+ return mLogSessionId != null ? mLogSessionId.getStringId() : "";
+ }
+
// Private classes.
private static final class InputReadingDataReader implements DataReader {
@@ -2197,7 +2208,7 @@
// Native methods.
private native void nativeSubmitMetrics(
- // TODO: String logSessionId,
+ String logSessionId,
String parserName,
boolean createdByName,
String parserPool,
diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java
index d7e9609..d1106a2 100644
--- a/apex/media/framework/java/android/media/MediaTranscodeManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
@@ -36,6 +37,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.modules.annotation.MinSdk;
+import com.android.modules.utils.build.SdkLevel;
import java.io.FileNotFoundException;
import java.lang.annotation.Retention;
@@ -119,6 +121,7 @@
private final String mPackageName;
private final int mPid;
private final int mUid;
+ private final boolean mIsLowRamDevice;
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
private final HashMap<Integer, TranscodingSession> mPendingTranscodingSessions = new HashMap();
private final Object mLock = new Object();
@@ -199,7 +202,16 @@
}
}
- private static IMediaTranscodingService getService(boolean retry) {
+ private IMediaTranscodingService getService(boolean retry) {
+ // Do not try to get the service on pre-S. The service is lazy-start and getting the
+ // service could block.
+ if (!SdkLevel.isAtLeastS()) {
+ return null;
+ }
+ // Do not try to get the service on AndroidGo (low-ram) devices.
+ if (mIsLowRamDevice) {
+ return null;
+ }
int retryCount = !retry ? 1 : CONNECT_SERVICE_RETRY_COUNT;
Log.i(TAG, "get service with retry " + retryCount);
for (int count = 1; count <= retryCount; count++) {
@@ -417,6 +429,7 @@
mPackageName = mContext.getPackageName();
mUid = Os.getuid();
mPid = Os.getpid();
+ mIsLowRamDevice = mContext.getSystemService(ActivityManager.class).isLowRamDevice();
IMediaTranscodingService service = getService(false /*retry*/);
if (service != null) {
mTranscodingClient = registerClient(service);
diff --git a/apex/media/framework/jni/android_media_MediaParserJNI.cpp b/apex/media/framework/jni/android_media_MediaParserJNI.cpp
index 7fc4628..c81152c 100644
--- a/apex/media/framework/jni/android_media_MediaParserJNI.cpp
+++ b/apex/media/framework/jni/android_media_MediaParserJNI.cpp
@@ -29,6 +29,7 @@
constexpr char kMediaMetricsKey[] = "mediaparser";
+constexpr char kAttributeLogSessionId[] = "android.media.mediaparser.logSessionId";
constexpr char kAttributeParserName[] = "android.media.mediaparser.parserName";
constexpr char kAttributeCreatedByName[] = "android.media.mediaparser.createdByName";
constexpr char kAttributeParserPool[] = "android.media.mediaparser.parserPool";
@@ -65,11 +66,14 @@
} // namespace
-JNI_FUNCTION(void, nativeSubmitMetrics, jstring parserNameJstring, jboolean createdByName,
- jstring parserPoolJstring, jstring lastExceptionJstring, jlong resourceByteCount,
- jlong durationMillis, jstring trackMimeTypesJstring, jstring trackCodecsJstring,
- jstring alteredParameters, jint videoWidth, jint videoHeight) {
+JNI_FUNCTION(void, nativeSubmitMetrics, jstring logSessionIdJstring, jstring parserNameJstring,
+ jboolean createdByName, jstring parserPoolJstring, jstring lastExceptionJstring,
+ jlong resourceByteCount, jlong durationMillis, jstring trackMimeTypesJstring,
+ jstring trackCodecsJstring, jstring alteredParameters, jint videoWidth,
+ jint videoHeight) {
mediametrics_handle_t item(mediametrics_create(kMediaMetricsKey));
+ mediametrics_setCString(item, kAttributeLogSessionId,
+ JstringHandle(env, logSessionIdJstring).value());
mediametrics_setCString(item, kAttributeParserName,
JstringHandle(env, parserNameJstring).value());
mediametrics_setInt32(item, kAttributeCreatedByName, createdByName ? 1 : 0);
diff --git a/cmds/bootanimation/BootAnimationUtil.cpp b/cmds/bootanimation/BootAnimationUtil.cpp
index 1e417e9..4f56e5a 100644
--- a/cmds/bootanimation/BootAnimationUtil.cpp
+++ b/cmds/bootanimation/BootAnimationUtil.cpp
@@ -49,7 +49,14 @@
}
property_get("ro.boot.quiescent", value, "0");
- return atoi(value) > 0;
+ if (atoi(value) > 0) {
+ // Only show the bootanimation for quiescent boots if this system property is set to enabled
+ if (!property_get_bool("ro.bootanim.quiescent.enabled", false)) {
+ return true;
+ }
+ }
+
+ return false;
}
void waitForSurfaceFlinger() {
diff --git a/cmds/dpm/Android.bp b/cmds/dpm/Android.bp
index 6819d09..665abcd 100644
--- a/cmds/dpm/Android.bp
+++ b/cmds/dpm/Android.bp
@@ -18,7 +18,8 @@
],
}
-sh_binary {
+java_binary {
name: "dpm",
- src: "dpm",
+ wrapper: "dpm",
+ srcs: ["**/*.java"],
}
diff --git a/cmds/dpm/dpm b/cmds/dpm/dpm
index 784db5b..e0efdc1 100755
--- a/cmds/dpm/dpm
+++ b/cmds/dpm/dpm
@@ -1,5 +1,7 @@
#!/system/bin/sh
# Script to start "dpm" on the device
#
-cmd device_policy "$@"
+base=/system
+export CLASSPATH=$base/framework/dpm.jar
+exec app_process $base/bin com.android.commands.dpm.Dpm "$@"
diff --git a/cmds/dpm/src/com/android/commands/dpm/Dpm.java b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
new file mode 100644
index 0000000..d0c2a24
--- /dev/null
+++ b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.commands.dpm;
+
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.IDevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+
+import com.android.internal.os.BaseCommand;
+
+import java.io.PrintStream;
+
+public final class Dpm extends BaseCommand {
+
+ /**
+ * Command-line entry point.
+ *
+ * @param args The command-line arguments
+ */
+ public static void main(String[] args) {
+ (new Dpm()).run(args);
+ }
+
+ private static final String COMMAND_SET_ACTIVE_ADMIN = "set-active-admin";
+ private static final String COMMAND_SET_DEVICE_OWNER = "set-device-owner";
+ private static final String COMMAND_SET_PROFILE_OWNER = "set-profile-owner";
+ private static final String COMMAND_REMOVE_ACTIVE_ADMIN = "remove-active-admin";
+ private static final String COMMAND_CLEAR_FREEZE_PERIOD_RECORD = "clear-freeze-period-record";
+ private static final String COMMAND_FORCE_NETWORK_LOGS = "force-network-logs";
+ private static final String COMMAND_FORCE_SECURITY_LOGS = "force-security-logs";
+ private static final String COMMAND_MARK_PO_ON_ORG_OWNED_DEVICE =
+ "mark-profile-owner-on-organization-owned-device";
+
+ private IDevicePolicyManager mDevicePolicyManager;
+ private int mUserId = UserHandle.USER_SYSTEM;
+ private String mName = "";
+ private ComponentName mComponent = null;
+
+ @Override
+ public void onShowUsage(PrintStream out) {
+ out.println(
+ "usage: dpm [subcommand] [options]\n" +
+ "usage: dpm set-active-admin [ --user <USER_ID> | current ] <COMPONENT>\n" +
+ // STOPSHIP Finalize it
+ "usage: dpm set-device-owner [ --user <USER_ID> | current *EXPERIMENTAL* ] " +
+ "[ --name <NAME> ] <COMPONENT>\n" +
+ "usage: dpm set-profile-owner [ --user <USER_ID> | current ] [ --name <NAME> ] " +
+ "<COMPONENT>\n" +
+ "usage: dpm remove-active-admin [ --user <USER_ID> | current ] [ --name <NAME> ] " +
+ "<COMPONENT>\n" +
+ "\n" +
+ "dpm set-active-admin: Sets the given component as active admin" +
+ " for an existing user.\n" +
+ "\n" +
+ "dpm set-device-owner: Sets the given component as active admin, and its" +
+ " package as device owner.\n" +
+ "\n" +
+ "dpm set-profile-owner: Sets the given component as active admin and profile" +
+ " owner for an existing user.\n" +
+ "\n" +
+ "dpm remove-active-admin: Disables an active admin, the admin must have declared" +
+ " android:testOnly in the application in its manifest. This will also remove" +
+ " device and profile owners.\n" +
+ "\n" +
+ "dpm " + COMMAND_CLEAR_FREEZE_PERIOD_RECORD + ": clears framework-maintained " +
+ "record of past freeze periods that the device went through. For use during " +
+ "feature development to prevent triggering restriction on setting freeze " +
+ "periods.\n" +
+ "\n" +
+ "dpm " + COMMAND_FORCE_NETWORK_LOGS + ": makes all network logs available to " +
+ "the DPC and triggers DeviceAdminReceiver.onNetworkLogsAvailable() if needed.\n" +
+ "\n" +
+ "dpm " + COMMAND_FORCE_SECURITY_LOGS + ": makes all security logs available to " +
+ "the DPC and triggers DeviceAdminReceiver.onSecurityLogsAvailable() if needed."
+ + "\n"
+ + "usage: dpm " + COMMAND_MARK_PO_ON_ORG_OWNED_DEVICE + ": "
+ + "[ --user <USER_ID> | current ] <COMPONENT>\n");
+ }
+
+ @Override
+ public void onRun() throws Exception {
+ mDevicePolicyManager = IDevicePolicyManager.Stub.asInterface(
+ ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
+ if (mDevicePolicyManager == null) {
+ showError("Error: Could not access the Device Policy Manager. Is the system running?");
+ return;
+ }
+
+ String command = nextArgRequired();
+ switch (command) {
+ case COMMAND_SET_ACTIVE_ADMIN:
+ runSetActiveAdmin();
+ break;
+ case COMMAND_SET_DEVICE_OWNER:
+ runSetDeviceOwner();
+ break;
+ case COMMAND_SET_PROFILE_OWNER:
+ runSetProfileOwner();
+ break;
+ case COMMAND_REMOVE_ACTIVE_ADMIN:
+ runRemoveActiveAdmin();
+ break;
+ case COMMAND_CLEAR_FREEZE_PERIOD_RECORD:
+ runClearFreezePeriodRecord();
+ break;
+ case COMMAND_FORCE_NETWORK_LOGS:
+ runForceNetworkLogs();
+ break;
+ case COMMAND_FORCE_SECURITY_LOGS:
+ runForceSecurityLogs();
+ break;
+ case COMMAND_MARK_PO_ON_ORG_OWNED_DEVICE:
+ runMarkProfileOwnerOnOrganizationOwnedDevice();
+ break;
+ default:
+ throw new IllegalArgumentException ("unknown command '" + command + "'");
+ }
+ }
+
+ private void runForceNetworkLogs() throws RemoteException, InterruptedException {
+ while (true) {
+ final long toWait = mDevicePolicyManager.forceNetworkLogs();
+ if (toWait == 0) {
+ break;
+ }
+ System.out.println("We have to wait for " + toWait + " milliseconds...");
+ Thread.sleep(toWait);
+ }
+ System.out.println("Success");
+ }
+
+ private void runForceSecurityLogs() throws RemoteException, InterruptedException {
+ while (true) {
+ final long toWait = mDevicePolicyManager.forceSecurityLogs();
+ if (toWait == 0) {
+ break;
+ }
+ System.out.println("We have to wait for " + toWait + " milliseconds...");
+ Thread.sleep(toWait);
+ }
+ System.out.println("Success");
+ }
+
+ private void parseArgs(boolean canHaveName) {
+ String opt;
+ while ((opt = nextOption()) != null) {
+ if ("--user".equals(opt)) {
+ String arg = nextArgRequired();
+ if ("current".equals(arg) || "cur".equals(arg)) {
+ mUserId = UserHandle.USER_CURRENT;
+ } else {
+ mUserId = parseInt(arg);
+ }
+ if (mUserId == UserHandle.USER_CURRENT) {
+ IActivityManager activityManager = ActivityManager.getService();
+ try {
+ mUserId = activityManager.getCurrentUser().id;
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+ } else if (canHaveName && "--name".equals(opt)) {
+ mName = nextArgRequired();
+ } else {
+ throw new IllegalArgumentException("Unknown option: " + opt);
+ }
+ }
+ mComponent = parseComponentName(nextArgRequired());
+ }
+
+ private void runSetActiveAdmin() throws RemoteException {
+ parseArgs(/*canHaveName=*/ false);
+ mDevicePolicyManager.setActiveAdmin(mComponent, true /*refreshing*/, mUserId);
+
+ System.out.println("Success: Active admin set to component " + mComponent.toShortString());
+ }
+
+ private void runSetDeviceOwner() throws RemoteException {
+ parseArgs(/*canHaveName=*/ true);
+ mDevicePolicyManager.setActiveAdmin(mComponent, true /*refreshing*/, mUserId);
+
+ try {
+ if (!mDevicePolicyManager.setDeviceOwner(mComponent, mName, mUserId)) {
+ throw new RuntimeException(
+ "Can't set package " + mComponent + " as device owner.");
+ }
+ } catch (Exception e) {
+ // Need to remove the admin that we just added.
+ mDevicePolicyManager.removeActiveAdmin(mComponent, UserHandle.USER_SYSTEM);
+ throw e;
+ }
+
+ mDevicePolicyManager.setUserProvisioningState(
+ DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId);
+
+ System.out.println("Success: Device owner set to package " + mComponent);
+ System.out.println("Active admin set to component " + mComponent.toShortString());
+ }
+
+ private void runRemoveActiveAdmin() throws RemoteException {
+ parseArgs(/*canHaveName=*/ false);
+ mDevicePolicyManager.forceRemoveActiveAdmin(mComponent, mUserId);
+ System.out.println("Success: Admin removed " + mComponent);
+ }
+
+ private void runSetProfileOwner() throws RemoteException {
+ parseArgs(/*canHaveName=*/ true);
+ mDevicePolicyManager.setActiveAdmin(mComponent, true /*refreshing*/, mUserId);
+
+ try {
+ if (!mDevicePolicyManager.setProfileOwner(mComponent, mName, mUserId)) {
+ throw new RuntimeException("Can't set component " + mComponent.toShortString() +
+ " as profile owner for user " + mUserId);
+ }
+ } catch (Exception e) {
+ // Need to remove the admin that we just added.
+ mDevicePolicyManager.removeActiveAdmin(mComponent, mUserId);
+ throw e;
+ }
+
+ mDevicePolicyManager.setUserProvisioningState(
+ DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId);
+
+ System.out.println("Success: Active admin and profile owner set to "
+ + mComponent.toShortString() + " for user " + mUserId);
+ }
+
+ private void runClearFreezePeriodRecord() throws RemoteException {
+ mDevicePolicyManager.clearSystemUpdatePolicyFreezePeriodRecord();
+ System.out.println("Success");
+ }
+
+
+ private void runMarkProfileOwnerOnOrganizationOwnedDevice() throws RemoteException {
+ parseArgs(/*canHaveName=*/ false);
+ mDevicePolicyManager.markProfileOwnerOnOrganizationOwnedDevice(mComponent, mUserId);
+ System.out.println("Success");
+ }
+
+ private ComponentName parseComponentName(String component) {
+ ComponentName cn = ComponentName.unflattenFromString(component);
+ if (cn == null) {
+ throw new IllegalArgumentException ("Invalid component " + component);
+ }
+ return cn;
+ }
+
+ private int parseInt(String argument) {
+ try {
+ return Integer.parseInt(argument);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException ("Invalid integer argument '" + argument + "'", e);
+ }
+ }
+}
diff --git a/cmds/idmap2/idmap2d/aidl/services/android/os/OverlayablePolicy.aidl b/cmds/idmap2/idmap2d/aidl/services/android/os/OverlayablePolicy.aidl
index 403d8c5..a47b8416 100644
--- a/cmds/idmap2/idmap2d/aidl/services/android/os/OverlayablePolicy.aidl
+++ b/cmds/idmap2/idmap2d/aidl/services/android/os/OverlayablePolicy.aidl
@@ -20,14 +20,16 @@
* @see ResourcesTypes.h ResTable_overlayable_policy_header::PolicyFlags
* @hide
*/
-interface OverlayablePolicy {
- const int PUBLIC = 0x00000001;
- const int SYSTEM_PARTITION = 0x00000002;
- const int VENDOR_PARTITION = 0x00000004;
- const int PRODUCT_PARTITION = 0x00000008;
- const int SIGNATURE = 0x00000010;
- const int ODM_PARTITION = 0x00000020;
- const int OEM_PARTITION = 0x00000040;
- const int ACTOR_SIGNATURE = 0x00000080;
- const int CONFIG_SIGNATURE = 0x0000100;
+@Backing(type="int")
+enum OverlayablePolicy {
+ NONE = 0x00000000,
+ PUBLIC = 0x00000001,
+ SYSTEM_PARTITION = 0x00000002,
+ VENDOR_PARTITION = 0x00000004,
+ PRODUCT_PARTITION = 0x00000008,
+ SIGNATURE = 0x00000010,
+ ODM_PARTITION = 0x00000020,
+ OEM_PARTITION = 0x00000040,
+ ACTOR_SIGNATURE = 0x00000080,
+ CONFIG_SIGNATURE = 0x0000100,
}
diff --git a/core/api/current.txt b/core/api/current.txt
index a2e0ed8..b223bc6 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9,6 +9,7 @@
ctor public Manifest.permission();
field public static final String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER";
field public static final String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION";
+ field public static final String ACCESS_BLOBS_ACROSS_USERS = "android.permission.ACCESS_BLOBS_ACROSS_USERS";
field public static final String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
field public static final String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
field public static final String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
@@ -8633,7 +8634,7 @@
method public android.bluetooth.le.BluetoothLeAdvertiser getBluetoothLeAdvertiser();
method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
- method public static android.bluetooth.BluetoothAdapter getDefaultAdapter();
+ method @Deprecated public static android.bluetooth.BluetoothAdapter getDefaultAdapter();
method public int getLeMaximumAdvertisingDataLength();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getName();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getProfileConnectionState(int);
@@ -18046,7 +18047,7 @@
}
public final class CameraExtensionCharacteristics {
- method @Nullable public android.util.Range<java.lang.Long> getEstimatedCaptureLatencyRange(int, @NonNull android.util.Size, int);
+ method @Nullable public android.util.Range<java.lang.Long> getEstimatedCaptureLatencyRangeMillis(int, @NonNull android.util.Size, int);
method @NonNull public <T> java.util.List<android.util.Size> getExtensionSupportedSizes(int, @NonNull Class<T>);
method @NonNull public java.util.List<android.util.Size> getExtensionSupportedSizes(int, int);
method @NonNull public java.util.List<java.lang.Integer> getSupportedExtensions();
@@ -18963,22 +18964,27 @@
method public int getType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.Light> CREATOR;
- field public static final int LIGHT_TYPE_INPUT_PLAYER_ID = 10; // 0xa
- field public static final int LIGHT_TYPE_INPUT_RGB = 11; // 0xb
- field public static final int LIGHT_TYPE_INPUT_SINGLE = 9; // 0x9
+ field public static final int LIGHT_TYPE_INPUT_PLAYER_ID = 10002; // 0x2712
+ field public static final int LIGHT_TYPE_INPUT_RGB = 10003; // 0x2713
+ field public static final int LIGHT_TYPE_INPUT_SINGLE = 10001; // 0x2711
field public static final int LIGHT_TYPE_MICROPHONE = 8; // 0x8
}
public final class LightState implements android.os.Parcelable {
method public int describeContents();
- method @NonNull public static android.hardware.lights.LightState forColor(@ColorInt int);
- method @NonNull public static android.hardware.lights.LightState forPlayerId(int);
method @ColorInt public int getColor();
method public int getPlayerId();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.LightState> CREATOR;
}
+ public static final class LightState.Builder {
+ ctor public LightState.Builder();
+ method @NonNull public android.hardware.lights.LightState build();
+ method @NonNull public android.hardware.lights.LightState.Builder setColor(@ColorInt int);
+ method @NonNull public android.hardware.lights.LightState.Builder setPlayerId(int);
+ }
+
public abstract class LightsManager {
method @NonNull public abstract android.hardware.lights.LightState getLightState(@NonNull android.hardware.lights.Light);
method @NonNull public abstract java.util.List<android.hardware.lights.Light> getLights();
@@ -18994,6 +19000,7 @@
public final class LightsRequest {
method @NonNull public java.util.List<android.hardware.lights.LightState> getLightStates();
method @NonNull public java.util.List<java.lang.Integer> getLights();
+ method @NonNull public java.util.Map<java.lang.Integer,android.hardware.lights.LightState> getLightsAndStates();
}
public static final class LightsRequest.Builder {
@@ -19314,7 +19321,7 @@
method public void appPrivateCommand(String, android.os.Bundle);
method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
method public void finishInput();
- method public void toggleSoftInput(int, int);
+ method @Deprecated public void toggleSoftInput(int, int);
method public void updateCursor(android.graphics.Rect);
method public void updateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
method public void updateExtractedText(int, android.view.inputmethod.ExtractedText);
@@ -26455,7 +26462,6 @@
method @Deprecated public static int getDefaultPort();
method @Deprecated public static String getHost(android.content.Context);
method @Deprecated public static int getPort(android.content.Context);
- field @Deprecated public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
field public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
}
@@ -26541,9 +26547,6 @@
field public static final int UNSUPPORTED = -1; // 0xffffffff
}
- public interface TunnelConnectionParams {
- }
-
public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable {
method public abstract android.net.Uri.Builder buildUpon();
method public int compareTo(android.net.Uri);
@@ -27112,7 +27115,7 @@
}
public static final class VcnGatewayConnectionConfig.Builder {
- ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.TunnelConnectionParams);
+ ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.ipsec.ike.IkeTunnelConnectionParams);
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int);
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build();
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int);
@@ -51999,8 +52002,8 @@
method @Deprecated public void showStatusIcon(android.os.IBinder, String, @DrawableRes int);
method @Deprecated public boolean switchToLastInputMethod(android.os.IBinder);
method @Deprecated public boolean switchToNextInputMethod(android.os.IBinder, boolean);
- method public void toggleSoftInput(int, int);
- method public void toggleSoftInputFromWindow(android.os.IBinder, int, int);
+ method @Deprecated public void toggleSoftInput(int, int);
+ method @Deprecated public void toggleSoftInputFromWindow(android.os.IBinder, int, int);
method @Deprecated public void updateCursor(android.view.View, int, int, int, int);
method public void updateCursorAnchorInfo(android.view.View, android.view.inputmethod.CursorAnchorInfo);
method public void updateExtractedText(android.view.View, int, android.view.inputmethod.ExtractedText);
@@ -52023,7 +52026,7 @@
method public void dispatchTrackballEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
method public void finishInput();
- method public void toggleSoftInput(int, int);
+ method @Deprecated public void toggleSoftInput(int, int);
method public void updateCursor(android.graphics.Rect);
method public void updateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
method public void updateExtractedText(int, android.view.inputmethod.ExtractedText);
@@ -52835,15 +52838,18 @@
}
public final class TranslationManager {
- method public void addOnDeviceTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent);
+ method public void addOnDeviceTranslationCapabilityUpdateListener(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.translation.TranslationCapability>);
+ method @Deprecated public void addOnDeviceTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent);
method @Deprecated public void addTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent);
- method @Nullable @WorkerThread public android.view.translation.Translator createOnDeviceTranslator(@NonNull android.view.translation.TranslationContext);
+ method public void createOnDeviceTranslator(@NonNull android.view.translation.TranslationContext, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.translation.Translator>);
+ method @Deprecated @Nullable @WorkerThread public android.view.translation.Translator createOnDeviceTranslator(@NonNull android.view.translation.TranslationContext);
method @Deprecated @Nullable @WorkerThread public android.view.translation.Translator createTranslator(@NonNull android.view.translation.TranslationContext);
method @NonNull @WorkerThread public java.util.Set<android.view.translation.TranslationCapability> getOnDeviceTranslationCapabilities(int, int);
method @Nullable public android.app.PendingIntent getOnDeviceTranslationSettingsActivityIntent();
method @Deprecated @NonNull @WorkerThread public java.util.Set<android.view.translation.TranslationCapability> getTranslationCapabilities(int, int);
method @Deprecated @Nullable public android.app.PendingIntent getTranslationSettingsActivityIntent();
- method public void removeOnDeviceTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent);
+ method public void removeOnDeviceTranslationCapabilityUpdateListener(@NonNull java.util.function.Consumer<android.view.translation.TranslationCapability>);
+ method @Deprecated public void removeOnDeviceTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent);
method @Deprecated public void removeTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent);
}
@@ -56792,6 +56798,7 @@
public interface SplashScreen {
method public void clearOnExitAnimationListener();
method public void setOnExitAnimationListener(@NonNull android.window.SplashScreen.OnExitAnimationListener);
+ method public void setSplashScreenTheme(@StyleRes int);
}
public static interface SplashScreen.OnExitAnimationListener {
diff --git a/core/api/removed.txt b/core/api/removed.txt
index ef35c59..cdaa5f53 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -252,6 +252,10 @@
@IntDef({0x0, 0xa, 0x14, 0x1e}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NetworkBadging.Badging {
}
+ public final class Proxy {
+ field @Deprecated public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
+ }
+
@Deprecated public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
method @Deprecated public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index a4fdc33..22af3f7 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3,7 +3,6 @@
public static final class Manifest.permission {
field public static final String ACCESS_AMBIENT_LIGHT_STATS = "android.permission.ACCESS_AMBIENT_LIGHT_STATS";
- field public static final String ACCESS_BLOBS_ACROSS_USERS = "android.permission.ACCESS_BLOBS_ACROSS_USERS";
field public static final String ACCESS_BROADCAST_RADIO = "android.permission.ACCESS_BROADCAST_RADIO";
field public static final String ACCESS_CACHE_FILESYSTEM = "android.permission.ACCESS_CACHE_FILESYSTEM";
field public static final String ACCESS_CONTEXT_HUB = "android.permission.ACCESS_CONTEXT_HUB";
@@ -1901,10 +1900,10 @@
package android.bluetooth {
public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
- method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public android.bluetooth.BufferConstraints getBufferConstraints();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getDynamicBufferSupport();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBufferLengthMillis(int, int);
+ method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.bluetooth.BufferConstraints getBufferConstraints();
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getDynamicBufferSupport();
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setBufferLengthMillis(int, int);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; // 0x1
field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; // 0x2
@@ -1919,8 +1918,8 @@
public final class BluetoothA2dpSink implements android.bluetooth.BluetoothProfile {
method public void finalize();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isAudioPlaying(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean isAudioPlaying(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
}
@@ -2008,13 +2007,13 @@
public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean connect(android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
}
public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public long getHiSyncId(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public long getHiSyncId(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
}
@@ -2024,9 +2023,9 @@
public final class BluetoothHidHost implements android.bluetooth.BluetoothProfile {
method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
}
@@ -2045,7 +2044,7 @@
public final class BluetoothPan implements android.bluetooth.BluetoothProfile {
method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isTetheringOn();
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.TETHER_PRIVILEGED}) public void setBluetoothTethering(boolean);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
@@ -2063,7 +2062,7 @@
}
public class BluetoothPbap implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
}
@@ -8832,8 +8831,8 @@
public final class PermissionControllerManager {
method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void applyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING) public void getGroupOfPlatformPermission(@NonNull String, @NonNull java.util.function.Consumer<java.lang.String>);
- method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING) public void getPlatformPermissionsForGroup(@NonNull String, @NonNull java.util.function.Consumer<java.util.List<java.lang.String>>);
+ method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING) public void getGroupOfPlatformPermission(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.String>);
+ method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING) public void getPlatformPermissionsForGroup(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<java.lang.String>>);
method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getRuntimePermissionBackup(@NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<byte[]>);
method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[], @NonNull android.os.UserHandle);
@@ -10514,6 +10513,7 @@
method public static int getMaxBundleSize();
method public static int getMaxHotwordPhraseId();
method public static int getMaxScore();
+ method @Nullable public android.media.MediaSyncEvent getMediaSyncEvent();
method public int getPersonalizedScore();
method public int getScore();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -10528,6 +10528,7 @@
method @NonNull public android.service.voice.HotwordDetectedResult.Builder setConfidenceLevel(int);
method @NonNull public android.service.voice.HotwordDetectedResult.Builder setExtras(@NonNull android.os.PersistableBundle);
method @NonNull public android.service.voice.HotwordDetectedResult.Builder setHotwordPhraseId(int);
+ method @NonNull public android.service.voice.HotwordDetectedResult.Builder setMediaSyncEvent(@NonNull android.media.MediaSyncEvent);
method @NonNull public android.service.voice.HotwordDetectedResult.Builder setPersonalizedScore(int);
method @NonNull public android.service.voice.HotwordDetectedResult.Builder setScore(int);
}
@@ -10535,8 +10536,10 @@
public abstract class HotwordDetectionService extends android.app.Service {
ctor public HotwordDetectionService();
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
- method public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, long, @NonNull android.service.voice.HotwordDetectionService.Callback);
- method public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @NonNull android.service.voice.HotwordDetectionService.Callback);
+ method @Deprecated public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, long, @NonNull android.service.voice.HotwordDetectionService.Callback);
+ method public void onDetect(@NonNull android.service.voice.AlwaysOnHotwordDetector.EventPayload, long, @NonNull android.service.voice.HotwordDetectionService.Callback);
+ method @Deprecated public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @NonNull android.service.voice.HotwordDetectionService.Callback);
+ method public void onDetect(@NonNull android.service.voice.HotwordDetectionService.Callback);
method public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle, @NonNull android.service.voice.HotwordDetectionService.Callback);
method public void onUpdateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, long, @Nullable java.util.function.IntConsumer);
field public static final int INITIALIZATION_STATUS_CUSTOM_ERROR_1 = 1; // 0x1
@@ -10582,7 +10585,8 @@
public class VoiceInteractionService extends android.app.Service {
method @NonNull public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, @Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, android.service.voice.AlwaysOnHotwordDetector.Callback);
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.HotwordDetector createHotwordDetector(@NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull android.service.voice.HotwordDetector.Callback);
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.HotwordDetector createHotwordDetector(@NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull android.service.voice.HotwordDetector.Callback);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.HotwordDetector createHotwordDetector(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull android.service.voice.HotwordDetector.Callback);
method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager();
}
@@ -14520,7 +14524,21 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void finishTranslation(@NonNull android.app.assist.ActivityId);
method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void pauseTranslation(@NonNull android.app.assist.ActivityId);
method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void resumeTranslation(@NonNull android.app.assist.ActivityId);
- method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void startTranslation(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.autofill.AutofillId>, @NonNull android.app.assist.ActivityId);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void startTranslation(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.autofill.AutofillId>, @NonNull android.app.assist.ActivityId);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void startTranslation(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.autofill.AutofillId>, @NonNull android.app.assist.ActivityId, @NonNull android.view.translation.UiTranslationSpec);
+ }
+
+ public final class UiTranslationSpec implements android.os.Parcelable {
+ method public int describeContents();
+ method public boolean shouldPadContentForCompat();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.UiTranslationSpec> CREATOR;
+ }
+
+ public static final class UiTranslationSpec.Builder {
+ ctor public UiTranslationSpec.Builder();
+ method @NonNull public android.view.translation.UiTranslationSpec build();
+ method @NonNull public android.view.translation.UiTranslationSpec.Builder setShouldPadContentForCompat(boolean);
}
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index d8c1387..dd97cda1 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -382,6 +382,7 @@
method @Deprecated public boolean revokeRuntimePermission(String, String, android.os.UserHandle);
method public void syncInputTransactions();
method public void syncInputTransactions(boolean);
+ method @Nullable public android.graphics.Bitmap takeScreenshot(@NonNull android.view.Window);
field @NonNull public static final java.util.Set<java.lang.String> ALL_PERMISSIONS;
}
@@ -2102,6 +2103,7 @@
field public static final String AUTOMATIC_POWER_SAVE_MODE = "automatic_power_save_mode";
field public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants";
field public static final String DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW = "enable_non_resizable_multi_window";
+ field public static final String DISABLE_WINDOW_BLURS = "disable_window_blurs";
field public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold";
field public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled";
field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
@@ -2779,7 +2781,6 @@
method public default void holdLock(android.os.IBinder, int);
method public default boolean isTaskSnapshotSupported();
method public default void setDisplayImePolicy(int, int);
- method public default void setForceCrossWindowBlurDisabled(boolean);
method public default void setShouldShowSystemDecors(int, boolean);
method public default void setShouldShowWithInsecureKeyguard(int, boolean);
method public default boolean shouldShowSystemDecors(int);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 6e0b83f..8f645c8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4416,11 +4416,20 @@
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
Application app = packageInfo.makeApplication(false, mInstrumentation);
- java.lang.ClassLoader cl = packageInfo.getClassLoader();
+
+ final java.lang.ClassLoader cl;
+ if (data.info.splitName != null) {
+ cl = packageInfo.getSplitClassLoader(data.info.splitName);
+ } else {
+ cl = packageInfo.getClassLoader();
+ }
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
- final ContextImpl context = ContextImpl.getImpl(service
+ ContextImpl context = ContextImpl.getImpl(service
.createServiceBaseContext(this, packageInfo));
+ if (data.info.splitName != null) {
+ context = (ContextImpl) context.createContextForSplit(data.info.splitName);
+ }
// Service resources must be initialized with the same loaders as the application
// context.
context.getResources().addLoaders(
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index c30bc24..623af5f 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -20,6 +20,7 @@
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.view.InputEvent;
+import android.view.SurfaceControl;
import android.view.WindowContentFrameStats;
import android.view.WindowAnimationFrameStats;
import android.os.ParcelFileDescriptor;
@@ -42,6 +43,7 @@
void syncInputTransactions(boolean waitForAnimations);
boolean setRotation(int rotation);
Bitmap takeScreenshot(in Rect crop);
+ Bitmap takeSurfaceControlScreenshot(in SurfaceControl surfaceControl);
boolean clearWindowContentFrameStats(int windowId);
WindowContentFrameStats getWindowContentFrameStats(int windowId);
void clearWindowAnimationFrameStats();
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 1765849..232b077 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -74,6 +74,9 @@
public static final int DISABLE_SEARCH = View.STATUS_BAR_DISABLE_SEARCH;
/** @hide */
+ public static final int DISABLE_ONGOING_CALL_CHIP = View.STATUS_BAR_DISABLE_ONGOING_CALL_CHIP;
+
+ /** @hide */
@Deprecated
public static final int DISABLE_NAVIGATION =
View.STATUS_BAR_DISABLE_HOME | View.STATUS_BAR_DISABLE_RECENT;
@@ -85,7 +88,7 @@
public static final int DISABLE_MASK = DISABLE_EXPAND | DISABLE_NOTIFICATION_ICONS
| DISABLE_NOTIFICATION_ALERTS | DISABLE_NOTIFICATION_TICKER
| DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK
- | DISABLE_SEARCH;
+ | DISABLE_SEARCH | DISABLE_ONGOING_CALL_CHIP;
/** @hide */
@IntDef(flag = true, prefix = {"DISABLE_"}, value = {
@@ -99,7 +102,8 @@
DISABLE_RECENT,
DISABLE_BACK,
DISABLE_CLOCK,
- DISABLE_SEARCH
+ DISABLE_SEARCH,
+ DISABLE_ONGOING_CALL_CHIP
})
@Retention(RetentionPolicy.SOURCE)
public @interface DisableFlags {}
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 7d3db5e..e0b484c 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -50,6 +50,10 @@
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewRootImpl;
+import android.view.Window;
import android.view.WindowAnimationFrameStats;
import android.view.WindowContentFrameStats;
import android.view.accessibility.AccessibilityEvent;
@@ -1012,7 +1016,7 @@
return null;
}
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error while taking screnshot!", re);
+ Log.e(LOG_TAG, "Error while taking screenshot!", re);
return null;
}
@@ -1023,6 +1027,51 @@
}
/**
+ * Used to capture a screenshot of a Window. This can return null in the following cases:
+ * 1. Window content hasn't been layed out.
+ * 2. Window doesn't have a valid SurfaceControl
+ * 3. An error occurred in SurfaceFlinger when trying to take the screenshot.
+ *
+ * @param window Window to take a screenshot of
+ *
+ * @return The screenshot bitmap on success, null otherwise.
+ *
+ * @hide
+ */
+ @TestApi
+ @Nullable
+ public Bitmap takeScreenshot(@NonNull Window window) {
+ if (window == null) {
+ return null;
+ }
+
+ View decorView = window.peekDecorView();
+ if (decorView == null) {
+ return null;
+ }
+
+ ViewRootImpl viewRoot = decorView.getViewRootImpl();
+ if (viewRoot == null) {
+ return null;
+ }
+
+ SurfaceControl sc = viewRoot.getSurfaceControl();
+ if (!sc.isValid()) {
+ return null;
+ }
+
+ // Apply a sync transaction to ensure SurfaceFlinger is flushed before capturing a
+ // screenshot.
+ new SurfaceControl.Transaction().apply(true);
+ try {
+ return mUiAutomationConnection.takeSurfaceControlScreenshot(sc);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error while taking screenshot!", re);
+ return null;
+ }
+ }
+
+ /**
* Sets whether this UiAutomation to run in a "monkey" mode. Applications can query whether
* they are executed in a "monkey" mode, i.e. run by a test framework, and avoid doing
* potentially undesirable actions such as calling 911 or posting on public forums etc.
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 90210a9..e693c5e 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -18,6 +18,7 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceClient;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -206,6 +207,30 @@
}
}
+ @Nullable
+ @Override
+ public Bitmap takeSurfaceControlScreenshot(@NonNull SurfaceControl surfaceControl) {
+ synchronized (mLock) {
+ throwIfCalledByNotTrustedUidLocked();
+ throwIfShutdownLocked();
+ throwIfNotConnectedLocked();
+ }
+
+ SurfaceControl.ScreenshotHardwareBuffer captureBuffer;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ captureBuffer = SurfaceControl.captureLayers(
+ new SurfaceControl.LayerCaptureArgs.Builder(surfaceControl).build());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ if (captureBuffer == null) {
+ return null;
+ }
+ return captureBuffer.asBitmap();
+ }
+
@Override
public boolean clearWindowContentFrameStats(int windowId) throws RemoteException {
synchronized (mLock) {
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index 759597c..4c1a363 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -531,7 +531,7 @@
}
final PasswordMetrics enteredMetrics = computeForPasswordOrPin(password, isPin);
- return validatePasswordMetrics(adminMetrics, minComplexity, isPin, enteredMetrics);
+ return validatePasswordMetrics(adminMetrics, minComplexity, enteredMetrics);
}
/**
@@ -539,15 +539,13 @@
*
* @param adminMetrics - minimum metrics to satisfy admin requirements.
* @param minComplexity - minimum complexity imposed by the requester.
- * @param isPin - whether it is PIN that should be only digits
* @param actualMetrics - metrics for password to validate.
* @return a list of password validation errors. An empty list means the password is OK.
*
* TODO: move to PasswordPolicy
*/
public static List<PasswordValidationError> validatePasswordMetrics(
- PasswordMetrics adminMetrics, int minComplexity, boolean isPin,
- PasswordMetrics actualMetrics) {
+ PasswordMetrics adminMetrics, int minComplexity, PasswordMetrics actualMetrics) {
final ComplexityBucket bucket = ComplexityBucket.forComplexity(minComplexity);
// Make sure credential type is satisfactory.
@@ -561,7 +559,7 @@
return Collections.emptyList(); // Nothing to check for pattern or none.
}
- if (isPin && actualMetrics.nonNumeric > 0) {
+ if (actualMetrics.credType == CREDENTIAL_TYPE_PIN && actualMetrics.nonNumeric > 0) {
return Collections.singletonList(
new PasswordValidationError(CONTAINS_INVALID_CHARACTERS, 0));
}
diff --git a/core/java/android/app/people/ConversationStatus.java b/core/java/android/app/people/ConversationStatus.java
index d351683..8038158 100644
--- a/core/java/android/app/people/ConversationStatus.java
+++ b/core/java/android/app/people/ConversationStatus.java
@@ -142,32 +142,52 @@
dest.writeLong(mEndTimeMs);
}
+ /**
+ * Returns the unique identifier for the status.
+ */
public @NonNull String getId() {
return mId;
}
+ /**
+ * Returns the type of activity represented by this status
+ */
public @ActivityType int getActivity() {
return mActivity;
}
- public @Availability
- int getAvailability() {
+ /**
+ * Returns the availability of the people behind this conversation while this activity is
+ * happening.
+ */
+ public @Availability int getAvailability() {
return mAvailability;
}
- public @Nullable
- CharSequence getDescription() {
+ /**
+ * Returns the description for this activity.
+ */
+ public @Nullable CharSequence getDescription() {
return mDescription;
}
+ /**
+ * Returns the image for this activity.
+ */
public @Nullable Icon getIcon() {
return mIcon;
}
+ /**
+ * Returns the time at which this status started
+ */
public long getStartTimeMillis() {
return mStartTimeMs;
}
+ /**
+ * Returns the time at which this status should be expired.
+ */
public long getEndTimeMillis() {
return mEndTimeMs;
}
@@ -242,26 +262,51 @@
}
+ /**
+ * Sets the availability of the conversation to provide a hint about how likely
+ * it is that the user would receive a timely response if they sent a message.
+ */
public @NonNull Builder setAvailability(@Availability int availability) {
mAvailability = availability;
return this;
}
+ /**
+ * Sets a user visible description expanding on the conversation user(s)'s activity.
+ *
+ * <p>Examples include: what media someone is watching or listening to, their approximate
+ * location, or what type of anniversary they are celebrating.</p>
+ */
public @NonNull Builder setDescription(@Nullable CharSequence description) {
mDescription = description;
return this;
}
+ /**
+ * Sets an image representing the conversation user(s)'s activity.
+ *
+ * <p>Examples include: A still from a new story update, album art, or a map showing
+ * approximate location.</p>
+ */
public @NonNull Builder setIcon(@Nullable Icon icon) {
mIcon = icon;
return this;
}
+ /**
+ * Sets the time at which this status became valid.
+ */
public @NonNull Builder setStartTimeMillis(long startTimeMs) {
mStartTimeMs = startTimeMs;
return this;
}
+ /**
+ * Sets an expiration time for this status.
+ *
+ * <p>The system will remove the status at this time if it hasn't already been withdrawn.
+ * </p>
+ */
public @NonNull Builder setEndTimeMillis(long endTimeMs) {
mEndTimeMs = endTimeMs;
return this;
diff --git a/core/java/android/app/people/PeopleSpaceTile.java b/core/java/android/app/people/PeopleSpaceTile.java
index e645831..de3eeee 100644
--- a/core/java/android/app/people/PeopleSpaceTile.java
+++ b/core/java/android/app/people/PeopleSpaceTile.java
@@ -54,6 +54,7 @@
private boolean mIsImportantConversation;
private String mNotificationKey;
private CharSequence mNotificationContent;
+ private CharSequence mNotificationSender;
private String mNotificationCategory;
private Uri mNotificationDataUri;
private int mMessagesCount;
@@ -73,6 +74,7 @@
mIsImportantConversation = b.mIsImportantConversation;
mNotificationKey = b.mNotificationKey;
mNotificationContent = b.mNotificationContent;
+ mNotificationSender = b.mNotificationSender;
mNotificationCategory = b.mNotificationCategory;
mNotificationDataUri = b.mNotificationDataUri;
mMessagesCount = b.mMessagesCount;
@@ -134,6 +136,10 @@
return mNotificationContent;
}
+ public CharSequence getNotificationSender() {
+ return mNotificationSender;
+ }
+
public String getNotificationCategory() {
return mNotificationCategory;
}
@@ -170,7 +176,7 @@
/** Converts a {@link PeopleSpaceTile} into a {@link PeopleSpaceTile.Builder}. */
public Builder toBuilder() {
Builder builder =
- new Builder(mId, mUserName.toString(), mUserIcon, mIntent);
+ new Builder(mId, mUserName, mUserIcon, mIntent);
builder.setContactUri(mContactUri);
builder.setUserHandle(mUserHandle);
builder.setPackageName(mPackageName);
@@ -179,6 +185,7 @@
builder.setIsImportantConversation(mIsImportantConversation);
builder.setNotificationKey(mNotificationKey);
builder.setNotificationContent(mNotificationContent);
+ builder.setNotificationSender(mNotificationSender);
builder.setNotificationCategory(mNotificationCategory);
builder.setNotificationDataUri(mNotificationDataUri);
builder.setMessagesCount(mMessagesCount);
@@ -201,6 +208,7 @@
private boolean mIsImportantConversation;
private String mNotificationKey;
private CharSequence mNotificationContent;
+ private CharSequence mNotificationSender;
private String mNotificationCategory;
private Uri mNotificationDataUri;
private int mMessagesCount;
@@ -209,7 +217,7 @@
private List<ConversationStatus> mStatuses;
/** Builder for use only if a shortcut is not available for the tile. */
- public Builder(String id, String userName, Icon userIcon, Intent intent) {
+ public Builder(String id, CharSequence userName, Icon userIcon, Intent intent) {
mId = id;
mUserName = userName;
mUserIcon = userIcon;
@@ -316,6 +324,12 @@
return this;
}
+ /** Sets the associated notification's sender. */
+ public Builder setNotificationSender(CharSequence notificationSender) {
+ mNotificationSender = notificationSender;
+ return this;
+ }
+
/** Sets the associated notification's category. */
public Builder setNotificationCategory(String notificationCategory) {
mNotificationCategory = notificationCategory;
@@ -371,6 +385,7 @@
mIsImportantConversation = in.readBoolean();
mNotificationKey = in.readString();
mNotificationContent = in.readCharSequence();
+ mNotificationSender = in.readCharSequence();
mNotificationCategory = in.readString();
mNotificationDataUri = in.readParcelable(Uri.class.getClassLoader());
mMessagesCount = in.readInt();
@@ -398,6 +413,7 @@
dest.writeBoolean(mIsImportantConversation);
dest.writeString(mNotificationKey);
dest.writeCharSequence(mNotificationContent);
+ dest.writeCharSequence(mNotificationSender);
dest.writeString(mNotificationCategory);
dest.writeParcelable(mNotificationDataUri, flags);
dest.writeInt(mMessagesCount);
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index c271862..1fb7638 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -23,13 +23,13 @@
import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
-import android.annotation.SuppressLint;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
import android.content.Context;
import android.os.Binder;
import android.os.Build;
@@ -265,7 +265,8 @@
@SystemApi
public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2;
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothA2dp> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.A2DP, "BluetoothA2dp",
IBluetoothA2dp.class.getName()) {
@@ -279,8 +280,10 @@
* Create a BluetoothA2dp proxy object for interacting with the local
* Bluetooth A2DP service.
*/
- /*package*/ BluetoothA2dp(Context context, ServiceListener listener) {
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ /* package */ BluetoothA2dp(Context context, ServiceListener listener,
+ BluetoothAdapter adapter) {
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
mProfileConnector.connect(context, listener);
}
@@ -386,7 +389,8 @@
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(), mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<BluetoothDevice>();
@@ -407,7 +411,8 @@
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states), mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<BluetoothDevice>();
@@ -468,7 +473,7 @@
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()
&& ((device == null) || isValidDevice(device))) {
- return service.setActiveDevice(device);
+ return service.setActiveDevice(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
@@ -495,7 +500,7 @@
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
- return service.getActiveDevice();
+ return service.getActiveDevice(mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return null;
@@ -555,7 +560,7 @@
&& connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
return false;
}
- return service.setConnectionPolicy(device, connectionPolicy);
+ return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
@@ -585,7 +590,8 @@
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()
&& isValidDevice(device)) {
- return BluetoothAdapter.connectionPolicyToPriority(service.getPriority(device));
+ return BluetoothAdapter.connectionPolicyToPriority(
+ service.getPriority(device, mAttributionSource));
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return BluetoothProfile.PRIORITY_OFF;
@@ -607,14 +613,18 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()
&& isValidDevice(device)) {
- return service.getConnectionPolicy(device);
+ return service.getConnectionPolicy(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
@@ -659,7 +669,7 @@
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
- service.setAvrcpAbsoluteVolume(volume);
+ service.setAvrcpAbsoluteVolume(volume, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
} catch (RemoteException e) {
@@ -680,7 +690,7 @@
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()
&& isValidDevice(device)) {
- return service.isA2dpPlaying(device);
+ return service.isA2dpPlaying(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
@@ -732,7 +742,7 @@
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
- return service.getCodecStatus(device);
+ return service.getCodecStatus(device, mAttributionSource);
}
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
@@ -767,7 +777,7 @@
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
- service.setCodecConfigPreference(device, codecConfig);
+ service.setCodecConfigPreference(device, codecConfig, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return;
@@ -824,9 +834,9 @@
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
if (enable) {
- service.enableOptionalCodecs(device);
+ service.enableOptionalCodecs(device, mAttributionSource);
} else {
- service.disableOptionalCodecs(device);
+ service.disableOptionalCodecs(device, mAttributionSource);
}
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
@@ -855,7 +865,7 @@
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
- return service.supportsOptionalCodecs(device);
+ return service.supportsOptionalCodecs(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
@@ -883,7 +893,7 @@
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
- return service.getOptionalCodecsEnabled(device);
+ return service.getOptionalCodecsEnabled(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return OPTIONAL_CODECS_PREF_UNKNOWN;
@@ -919,7 +929,7 @@
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()
&& isValidDevice(device)) {
- service.setOptionalCodecsEnabled(device, value);
+ service.setOptionalCodecsEnabled(device, value, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return;
@@ -941,13 +951,17 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @Type int getDynamicBufferSupport() {
if (VDBG) log("getDynamicBufferSupport()");
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
- return service.getDynamicBufferSupport();
+ return service.getDynamicBufferSupport(mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return DYNAMIC_BUFFER_SUPPORT_NONE;
@@ -968,13 +982,17 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @Nullable BufferConstraints getBufferConstraints() {
if (VDBG) log("getBufferConstraints()");
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
- return service.getBufferConstraints();
+ return service.getBufferConstraints(mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return null;
@@ -994,14 +1012,18 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setBufferLengthMillis(@BluetoothCodecConfig.SourceCodecType int codec,
int value) {
if (VDBG) log("setBufferLengthMillis(" + codec + ", " + value + ")");
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
- return service.setBufferLengthMillis(codec, value);
+ return service.setBufferLengthMillis(codec, value, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
index cbbf4c9..c0a2aa3 100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -27,6 +27,7 @@
import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
import android.content.Context;
import android.os.Binder;
import android.os.Build;
@@ -78,7 +79,8 @@
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothA2dpSink> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.A2DP_SINK,
"BluetoothA2dpSink", IBluetoothA2dpSink.class.getName()) {
@@ -92,8 +94,10 @@
* Create a BluetoothA2dp proxy object for interacting with the local
* Bluetooth A2DP service.
*/
- /*package*/ BluetoothA2dpSink(Context context, ServiceListener listener) {
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ /* package */ BluetoothA2dpSink(Context context, ServiceListener listener,
+ BluetoothAdapter adapter) {
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
mProfileConnector.connect(context, listener);
}
@@ -128,13 +132,17 @@
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.connect(device);
+ return service.connect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -175,7 +183,7 @@
final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.disconnect(device);
+ return service.disconnect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -198,7 +206,8 @@
final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled()) {
try {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(mAttributionSource), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -221,7 +230,9 @@
final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled()) {
try {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -244,7 +255,7 @@
final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionState(device);
+ return service.getConnectionState(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return BluetoothProfile.STATE_DISCONNECTED;
@@ -273,7 +284,7 @@
final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getAudioConfig(device);
+ return service.getAudioConfig(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return null;
@@ -332,7 +343,7 @@
return false;
}
try {
- return service.setConnectionPolicy(device, connectionPolicy);
+ return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -352,7 +363,11 @@
* @return priority of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
@@ -370,13 +385,17 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionPolicy(device);
+ return service.getConnectionPolicy(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
@@ -395,12 +414,16 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean isAudioPlaying(@NonNull BluetoothDevice device) {
final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.isA2dpPlaying(device);
+ return service.isA2dpPlaying(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 2426ead..8afc557 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -706,11 +706,13 @@
*/
private static BluetoothAdapter sAdapter;
- private static BluetoothLeScanner sBluetoothLeScanner;
- private static BluetoothLeAdvertiser sBluetoothLeAdvertiser;
- private static PeriodicAdvertisingManager sPeriodicAdvertisingManager;
+ private BluetoothLeScanner mBluetoothLeScanner;
+ private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
+ private PeriodicAdvertisingManager mPeriodicAdvertisingManager;
private final IBluetoothManager mManagerService;
+ private final AttributionSource mAttributionSource;
+
@UnsupportedAppUsage
private IBluetooth mService;
private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
@@ -722,8 +724,6 @@
private final Map<BluetoothConnectionCallback, Executor>
mBluetoothConnectionCallbackExecutorMap = new HashMap<>();
- private AttributionSource mAttributionSource;
-
/**
* Bluetooth metadata listener. Overrides the default BluetoothMetadataListener
* implementation.
@@ -752,27 +752,33 @@
/**
* Get a handle to the default local Bluetooth adapter.
- * <p>Currently Android only supports one Bluetooth adapter, but the API
- * could be extended to support more. This will always return the default
- * adapter.
+ * <p>
+ * Currently Android only supports one Bluetooth adapter, but the API could
+ * be extended to support more. This will always return the default adapter.
* </p>
*
- * @return the default local adapter, or null if Bluetooth is not supported on this hardware
- * platform
+ * @return the default local adapter, or null if Bluetooth is not supported
+ * on this hardware platform
+ * @deprecated this method will continue to work, but developers are
+ * strongly encouraged to migrate to using
+ * {@link BluetoothManager#getAdapter()}, since that approach
+ * enables support for {@link Context#createAttributionContext}.
*/
+ @Deprecated
@RequiresNoPermission
public static synchronized BluetoothAdapter getDefaultAdapter() {
if (sAdapter == null) {
- sAdapter = createAdapter();
+ sAdapter = createAdapter(BluetoothManager.resolveAttributionSource(null));
}
return sAdapter;
}
/** {@hide} */
- public static BluetoothAdapter createAdapter() {
+ public static BluetoothAdapter createAdapter(AttributionSource attributionSource) {
IBinder binder = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
if (binder != null) {
- return new BluetoothAdapter(IBluetoothManager.Stub.asInterface(binder));
+ return new BluetoothAdapter(IBluetoothManager.Stub.asInterface(binder),
+ attributionSource);
} else {
Log.e(TAG, "Bluetooth binder is null");
return null;
@@ -782,7 +788,7 @@
/**
* Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
*/
- BluetoothAdapter(IBluetoothManager managerService) {
+ BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource) {
if (managerService == null) {
throw new IllegalArgumentException("bluetooth manager service is null");
}
@@ -794,20 +800,12 @@
} finally {
mServiceLock.writeLock().unlock();
}
- mManagerService = managerService;
+ mManagerService = Objects.requireNonNull(managerService);
+ mAttributionSource = Objects.requireNonNull(attributionSource);
mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
mToken = new Binder();
}
- void setAttributionSource(AttributionSource attributionSource) {
- mAttributionSource = attributionSource;
- }
-
- private AttributionSource resolveAttributionSource() {
- return (mAttributionSource != null) ? mAttributionSource
- : ActivityThread.currentAttributionSource();
- }
-
/**
* Get a {@link BluetoothDevice} object for the given Bluetooth hardware
* address.
@@ -864,11 +862,11 @@
return null;
}
synchronized (mLock) {
- if (sBluetoothLeAdvertiser == null) {
- sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService);
+ if (mBluetoothLeAdvertiser == null) {
+ mBluetoothLeAdvertiser = new BluetoothLeAdvertiser(this);
}
+ return mBluetoothLeAdvertiser;
}
- return sBluetoothLeAdvertiser;
}
/**
@@ -892,11 +890,11 @@
}
synchronized (mLock) {
- if (sPeriodicAdvertisingManager == null) {
- sPeriodicAdvertisingManager = new PeriodicAdvertisingManager(mManagerService);
+ if (mPeriodicAdvertisingManager == null) {
+ mPeriodicAdvertisingManager = new PeriodicAdvertisingManager(this);
}
+ return mPeriodicAdvertisingManager;
}
- return sPeriodicAdvertisingManager;
}
/**
@@ -908,12 +906,11 @@
return null;
}
synchronized (mLock) {
- if (sBluetoothLeScanner == null) {
- sBluetoothLeScanner =
- new BluetoothLeScanner(mManagerService, resolveAttributionSource());
+ if (mBluetoothLeScanner == null) {
+ mBluetoothLeScanner = new BluetoothLeScanner(this);
}
+ return mBluetoothLeScanner;
}
- return sBluetoothLeScanner;
}
/**
@@ -984,7 +981,7 @@
}
String packageName = ActivityThread.currentPackageName();
try {
- return mManagerService.disableBle(packageName, mToken);
+ return mManagerService.disableBle(mAttributionSource, mToken);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1031,7 +1028,7 @@
}
String packageName = ActivityThread.currentPackageName();
try {
- return mManagerService.enableBle(packageName, mToken);
+ return mManagerService.enableBle(mAttributionSource, mToken);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1196,7 +1193,7 @@
return true;
}
try {
- return mManagerService.enable(ActivityThread.currentPackageName());
+ return mManagerService.enable(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1229,7 +1226,7 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disable() {
try {
- return mManagerService.disable(ActivityThread.currentPackageName(), true);
+ return mManagerService.disable(mAttributionSource, true);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1249,7 +1246,7 @@
public boolean disable(boolean persist) {
try {
- return mManagerService.disable(ActivityThread.currentPackageName(), persist);
+ return mManagerService.disable(mAttributionSource, persist);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1270,7 +1267,7 @@
})
public String getAddress() {
try {
- return mManagerService.getAddress();
+ return mManagerService.getAddress(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1288,7 +1285,7 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public String getName() {
try {
- return mManagerService.getName();
+ return mManagerService.getName(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1300,7 +1297,7 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public int getNameLengthForAdvertise() {
try {
- return mService.getNameLengthForAdvertise();
+ return mService.getNameLengthForAdvertise(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1319,7 +1316,8 @@
try {
mServiceLock.readLock().lock();
if (mService != null && mService.factoryReset()
- && mManagerService != null && mManagerService.onFactoryReset()) {
+ && mManagerService != null
+ && mManagerService.onFactoryReset(mAttributionSource)) {
return true;
}
Log.e(TAG, "factoryReset(): Setting persist.bluetooth.factoryreset to retry later");
@@ -1349,7 +1347,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.getUuids(resolveAttributionSource());
+ return mService.getUuids(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1383,7 +1381,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.setName(name, resolveAttributionSource());
+ return mService.setName(name, mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1411,7 +1409,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.getBluetoothClass(resolveAttributionSource());
+ return mService.getBluetoothClass(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1467,7 +1465,7 @@
if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.getIoCapability(resolveAttributionSource());
+ if (mService != null) return mService.getIoCapability(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.getMessage(), e);
} finally {
@@ -1520,7 +1518,7 @@
if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.getLeIoCapability(resolveAttributionSource());
+ if (mService != null) return mService.getLeIoCapability(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.getMessage(), e);
} finally {
@@ -1582,7 +1580,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.getScanMode(resolveAttributionSource());
+ return mService.getScanMode(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1631,7 +1629,7 @@
mServiceLock.readLock().lock();
if (mService != null) {
int durationSeconds = Math.toIntExact(durationMillis / 1000);
- return mService.setScanMode(mode, durationSeconds, resolveAttributionSource());
+ return mService.setScanMode(mode, durationSeconds, mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1681,7 +1679,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.setScanMode(mode, getDiscoverableTimeout(), resolveAttributionSource());
+ return mService.setScanMode(mode, getDiscoverableTimeout(), mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1702,7 +1700,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.getDiscoverableTimeout(resolveAttributionSource());
+ return mService.getDiscoverableTimeout(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1723,7 +1721,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- mService.setDiscoverableTimeout(timeout, resolveAttributionSource());
+ mService.setDiscoverableTimeout(timeout, mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1796,7 +1794,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.startDiscovery(resolveAttributionSource());
+ return mService.startDiscovery(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1832,7 +1830,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.cancelDiscovery(resolveAttributionSource());
+ return mService.cancelDiscovery(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1870,7 +1868,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.isDiscovering(resolveAttributionSource());
+ return mService.isDiscovering(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1913,7 +1911,7 @@
mServiceLock.readLock().lock();
if (mService != null) {
if (DBG) Log.d(TAG, "removeActiveDevice, profiles: " + profiles);
- return mService.removeActiveDevice(profiles);
+ return mService.removeActiveDevice(profiles, mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1965,7 +1963,7 @@
if (DBG) {
Log.d(TAG, "setActiveDevice, device: " + device + ", profiles: " + profiles);
}
- return mService.setActiveDevice(device, profiles);
+ return mService.setActiveDevice(device, profiles, mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1998,7 +1996,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.connectAllEnabledProfiles(device);
+ return mService.connectAllEnabledProfiles(device, mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -2030,7 +2028,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.disconnectAllEnabledProfiles(device);
+ return mService.disconnectAllEnabledProfiles(device, mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -2307,7 +2305,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.getMaxConnectedAudioDevices(resolveAttributionSource());
+ return mService.getMaxConnectedAudioDevices(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "failed to get getMaxConnectedAudioDevices, error: ", e);
@@ -2335,7 +2333,7 @@
// BLE is not supported
return false;
}
- return (iGatt.numHwTrackFiltersAvailable() != 0);
+ return (iGatt.numHwTrackFiltersAvailable(mAttributionSource) != 0);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -2419,7 +2417,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.getMostRecentlyConnectedDevices(resolveAttributionSource());
+ return mService.getMostRecentlyConnectedDevices(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -2449,7 +2447,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return toDeviceSet(mService.getBondedDevices(resolveAttributionSource()));
+ return toDeviceSet(mService.getBondedDevices(mAttributionSource));
}
return toDeviceSet(new BluetoothDevice[0]);
} catch (RemoteException e) {
@@ -2974,50 +2972,51 @@
}
if (profile == BluetoothProfile.HEADSET) {
- BluetoothHeadset headset = new BluetoothHeadset(context, listener);
+ BluetoothHeadset headset = new BluetoothHeadset(context, listener, this);
return true;
} else if (profile == BluetoothProfile.A2DP) {
- BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
+ BluetoothA2dp a2dp = new BluetoothA2dp(context, listener, this);
return true;
} else if (profile == BluetoothProfile.A2DP_SINK) {
- BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener);
+ BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener, this);
return true;
} else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
- BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);
+ BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener, this);
return true;
} else if (profile == BluetoothProfile.HID_HOST) {
- BluetoothHidHost iDev = new BluetoothHidHost(context, listener);
+ BluetoothHidHost iDev = new BluetoothHidHost(context, listener, this);
return true;
} else if (profile == BluetoothProfile.PAN) {
- BluetoothPan pan = new BluetoothPan(context, listener);
+ BluetoothPan pan = new BluetoothPan(context, listener, this);
return true;
} else if (profile == BluetoothProfile.PBAP) {
- BluetoothPbap pbap = new BluetoothPbap(context, listener);
+ BluetoothPbap pbap = new BluetoothPbap(context, listener, this);
return true;
} else if (profile == BluetoothProfile.HEALTH) {
Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated");
return false;
} else if (profile == BluetoothProfile.MAP) {
- BluetoothMap map = new BluetoothMap(context, listener);
+ BluetoothMap map = new BluetoothMap(context, listener, this);
return true;
} else if (profile == BluetoothProfile.HEADSET_CLIENT) {
- BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener);
+ BluetoothHeadsetClient headsetClient =
+ new BluetoothHeadsetClient(context, listener, this);
return true;
} else if (profile == BluetoothProfile.SAP) {
- BluetoothSap sap = new BluetoothSap(context, listener);
+ BluetoothSap sap = new BluetoothSap(context, listener, this);
return true;
} else if (profile == BluetoothProfile.PBAP_CLIENT) {
- BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener);
+ BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener, this);
return true;
} else if (profile == BluetoothProfile.MAP_CLIENT) {
- BluetoothMapClient mapClient = new BluetoothMapClient(context, listener);
+ BluetoothMapClient mapClient = new BluetoothMapClient(context, listener, this);
return true;
} else if (profile == BluetoothProfile.HID_DEVICE) {
- BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener);
+ BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener, this);
return true;
} else if (profile == BluetoothProfile.HEARING_AID) {
if (isHearingAidProfileSupported()) {
- BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener);
+ BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener, this);
return true;
}
return false;
@@ -3171,11 +3170,11 @@
if (mLeScanClients != null) {
mLeScanClients.clear();
}
- if (sBluetoothLeAdvertiser != null) {
- sBluetoothLeAdvertiser.cleanup();
+ if (mBluetoothLeAdvertiser != null) {
+ mBluetoothLeAdvertiser.cleanup();
}
- if (sBluetoothLeScanner != null) {
- sBluetoothLeScanner.cleanup();
+ if (mBluetoothLeScanner != null) {
+ mBluetoothLeScanner.cleanup();
}
} finally {
mServiceLock.writeLock().unlock();
@@ -3221,7 +3220,7 @@
return true;
}
try {
- return mManagerService.enableNoAutoConnect(ActivityThread.currentPackageName());
+ return mManagerService.enableNoAutoConnect(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -3514,11 +3513,17 @@
&& (Integer.parseInt(address.split(":")[5], 16) & 0b11) == 0b11;
}
+ /** {@hide} */
@UnsupportedAppUsage
- /*package*/ IBluetoothManager getBluetoothManager() {
+ public IBluetoothManager getBluetoothManager() {
return mManagerService;
}
+ /** {@hide} */
+ public AttributionSource getAttributionSource() {
+ return mAttributionSource;
+ }
+
private final ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks =
new ArrayList<IBluetoothManagerCallback>();
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
index cac676d..0b43e71 100644
--- a/core/java/android/bluetooth/BluetoothAvrcpController.java
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -22,6 +22,7 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
+import android.content.AttributionSource;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -86,7 +87,8 @@
public static final String EXTRA_PLAYER_SETTING =
"android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING";
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothAvrcpController> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.AVRCP_CONTROLLER,
"BluetoothAvrcpController", IBluetoothAvrcpController.class.getName()) {
@@ -101,8 +103,10 @@
* Create a BluetoothAvrcpController proxy object for interacting with the local
* Bluetooth AVRCP service.
*/
- /*package*/ BluetoothAvrcpController(Context context, ServiceListener listener) {
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ /* package */ BluetoothAvrcpController(Context context, ServiceListener listener,
+ BluetoothAdapter adapter) {
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
mProfileConnector.connect(context, listener);
}
@@ -131,7 +135,8 @@
getService();
if (service != null && isEnabled()) {
try {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(mAttributionSource), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -153,7 +158,9 @@
getService();
if (service != null && isEnabled()) {
try {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -175,7 +182,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionState(device);
+ return service.getConnectionState(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return BluetoothProfile.STATE_DISCONNECTED;
@@ -199,7 +206,7 @@
getService();
if (service != null && isEnabled()) {
try {
- settings = service.getPlayerSettings(device);
+ settings = service.getPlayerSettings(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in getMetadata() " + e);
return null;
@@ -220,7 +227,7 @@
getService();
if (service != null && isEnabled()) {
try {
- return service.setPlayerApplicationSetting(plAppSetting);
+ return service.setPlayerApplicationSetting(plAppSetting, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in setPlayerApplicationSetting() " + e);
return false;
@@ -243,7 +250,7 @@
getService();
if (service != null && isEnabled()) {
try {
- service.sendGroupNavigationCmd(device, keyCode, keyState);
+ service.sendGroupNavigationCmd(device, keyCode, keyState, mAttributionSource);
return;
} catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in sendGroupNavigationCmd()", e);
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index cc2ba9b..98823b09 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -24,7 +24,6 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
-import android.app.ActivityThread;
import android.app.PropertyInvalidatedCache;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
@@ -48,6 +47,7 @@
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
import java.util.UUID;
/**
@@ -1167,15 +1167,27 @@
mAddress = address;
mAddressType = ADDRESS_TYPE_PUBLIC;
+ mAttributionSource = BluetoothManager.resolveAttributionSource(null);
}
void setAttributionSource(AttributionSource attributionSource) {
mAttributionSource = attributionSource;
}
- private AttributionSource resolveAttributionSource() {
- return (mAttributionSource != null) ? mAttributionSource
- : ActivityThread.currentAttributionSource();
+ static BluetoothDevice setAttributionSource(BluetoothDevice device,
+ AttributionSource attributionSource) {
+ device.setAttributionSource(attributionSource);
+ return device;
+ }
+
+ static List<BluetoothDevice> setAttributionSource(List<BluetoothDevice> devices,
+ AttributionSource attributionSource) {
+ if (devices != null) {
+ for (BluetoothDevice device : devices) {
+ device.setAttributionSource(attributionSource);
+ }
+ }
+ return devices;
}
@Override
@@ -1268,7 +1280,7 @@
return null;
}
try {
- String name = service.getRemoteName(this, resolveAttributionSource());
+ String name = service.getRemoteName(this, mAttributionSource);
if (name != null) {
// remove whitespace characters from the name
return name
@@ -1299,7 +1311,7 @@
return DEVICE_TYPE_UNKNOWN;
}
try {
- return service.getRemoteType(this, resolveAttributionSource());
+ return service.getRemoteType(this, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1323,7 +1335,7 @@
return null;
}
try {
- String alias = service.getRemoteAliasWithAttribution(this, resolveAttributionSource());
+ String alias = service.getRemoteAliasWithAttribution(this, mAttributionSource);
if (alias == null) {
return getName();
}
@@ -1364,9 +1376,7 @@
return false;
}
try {
- return service.setRemoteAlias(this, alias,
- resolveAttributionSource().getPackageName(),
- resolveAttributionSource());
+ return service.setRemoteAlias(this, alias, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1392,7 +1402,7 @@
return BATTERY_LEVEL_BLUETOOTH_OFF;
}
try {
- return service.getBatteryLevel(this, resolveAttributionSource());
+ return service.getBatteryLevel(this, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1483,7 +1493,7 @@
}
try {
return service.createBond(
- this, transport, remoteP192Data, remoteP256Data, resolveAttributionSource());
+ this, transport, remoteP192Data, remoteP256Data, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1508,7 +1518,7 @@
return false;
}
try {
- return service.isBondingInitiatedLocally(this, resolveAttributionSource());
+ return service.isBondingInitiatedLocally(this, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1533,7 +1543,7 @@
Log.i(TAG, "cancelBondProcess() for device " + getAddress()
+ " called by pid: " + Process.myPid()
+ " tid: " + Process.myTid());
- return service.cancelBondProcess(this, resolveAttributionSource());
+ return service.cancelBondProcess(this, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1561,7 +1571,7 @@
Log.i(TAG, "removeBond() for device " + getAddress()
+ " called by pid: " + Process.myPid()
+ " tid: " + Process.myTid());
- return service.removeBond(this, resolveAttributionSource());
+ return service.removeBond(this, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1577,7 +1587,7 @@
@SuppressLint("AndroidFrameworkRequiresPermission")
protected Integer recompute(BluetoothDevice query) {
try {
- return sService.getBondState(query, resolveAttributionSource());
+ return sService.getBondState(query, mAttributionSource);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -1667,7 +1677,7 @@
return false;
}
try {
- return service.getConnectionStateWithAttribution(this, resolveAttributionSource())
+ return service.getConnectionStateWithAttribution(this, mAttributionSource)
!= CONNECTION_STATE_DISCONNECTED;
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1693,7 +1703,7 @@
return false;
}
try {
- return service.getConnectionStateWithAttribution(this, resolveAttributionSource())
+ return service.getConnectionStateWithAttribution(this, mAttributionSource)
> CONNECTION_STATE_CONNECTED;
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1716,7 +1726,7 @@
return null;
}
try {
- int classInt = service.getRemoteClass(this, resolveAttributionSource());
+ int classInt = service.getRemoteClass(this, mAttributionSource);
if (classInt == BluetoothClass.ERROR) return null;
return new BluetoothClass(classInt);
} catch (RemoteException e) {
@@ -1745,7 +1755,7 @@
return null;
}
try {
- return service.getRemoteUuids(this, resolveAttributionSource());
+ return service.getRemoteUuids(this, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1775,7 +1785,7 @@
return false;
}
try {
- return service.fetchRemoteUuidsWithAttribution(this, resolveAttributionSource());
+ return service.fetchRemoteUuidsWithAttribution(this, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1812,7 +1822,7 @@
return false;
}
try {
- return service.sdpSearch(this, uuid, resolveAttributionSource());
+ return service.sdpSearch(this, uuid, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1834,7 +1844,7 @@
return false;
}
try {
- return service.setPin(this, true, pin.length, pin, resolveAttributionSource());
+ return service.setPin(this, true, pin.length, pin, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1897,7 +1907,7 @@
return false;
}
try {
- return service.cancelBondProcess(this, resolveAttributionSource());
+ return service.cancelBondProcess(this, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1930,7 +1940,7 @@
return ACCESS_UNKNOWN;
}
try {
- return service.getPhonebookAccessPermission(this, resolveAttributionSource());
+ return service.getPhonebookAccessPermission(this, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -2036,7 +2046,7 @@
return ACCESS_UNKNOWN;
}
try {
- return service.getMessageAccessPermission(this, resolveAttributionSource());
+ return service.getMessageAccessPermission(this, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -2087,7 +2097,7 @@
return ACCESS_UNKNOWN;
}
try {
- return service.getSimAccessPermission(this, resolveAttributionSource());
+ return service.getSimAccessPermission(this, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -2516,7 +2526,8 @@
// BLE is not supported
return null;
}
- BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport, opportunistic, phy);
+ BluetoothGatt gatt = new BluetoothGatt(
+ iGatt, this, transport, opportunistic, phy, mAttributionSource);
gatt.connect(autoConnect, callback, handler);
return gatt;
} catch (RemoteException e) {
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 9d3eed8..aea8210 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -22,6 +22,7 @@
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
import android.os.Build;
import android.os.Handler;
import android.os.ParcelUuid;
@@ -69,6 +70,7 @@
private int mTransport;
private int mPhy;
private boolean mOpportunistic;
+ private final AttributionSource mAttributionSource;
private static final int AUTH_RETRY_STATE_IDLE = 0;
private static final int AUTH_RETRY_STATE_NO_MITM = 1;
@@ -198,7 +200,7 @@
try {
mService.clientConnect(mClientIf, mDevice.getAddress(),
!mAutoConnect, mTransport, mOpportunistic,
- mPhy); // autoConnect is inverse of "isDirect"
+ mPhy, mAttributionSource); // autoConnect is inverse of "isDirect"
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -376,7 +378,8 @@
try {
final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE)
? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
- mService.readCharacteristic(mClientIf, address, handle, authReq);
+ mService.readCharacteristic(
+ mClientIf, address, handle, authReq, mAttributionSource);
mAuthRetryState++;
return;
} catch (RemoteException e) {
@@ -439,7 +442,7 @@
? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
mService.writeCharacteristic(mClientIf, address, handle,
characteristic.getWriteType(), authReq,
- characteristic.getValue());
+ characteristic.getValue(), mAttributionSource);
mAuthRetryState++;
return;
} catch (RemoteException e) {
@@ -521,7 +524,8 @@
try {
final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE)
? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
- mService.readDescriptor(mClientIf, address, handle, authReq);
+ mService.readDescriptor(
+ mClientIf, address, handle, authReq, mAttributionSource);
mAuthRetryState++;
return;
} catch (RemoteException e) {
@@ -573,7 +577,7 @@
final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE)
? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
mService.writeDescriptor(mClientIf, address, handle,
- authReq, descriptor.getValue());
+ authReq, descriptor.getValue(), mAttributionSource);
mAuthRetryState++;
return;
} catch (RemoteException e) {
@@ -726,13 +730,14 @@
}
};
- /*package*/ BluetoothGatt(IBluetoothGatt iGatt, BluetoothDevice device,
- int transport, boolean opportunistic, int phy) {
+ /* package */ BluetoothGatt(IBluetoothGatt iGatt, BluetoothDevice device, int transport,
+ boolean opportunistic, int phy, AttributionSource attributionSource) {
mService = iGatt;
mDevice = device;
mTransport = transport;
mPhy = phy;
mOpportunistic = opportunistic;
+ mAttributionSource = attributionSource;
mServices = new ArrayList<BluetoothGattService>();
mConnState = CONN_STATE_IDLE;
@@ -867,7 +872,8 @@
if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid);
try {
- mService.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback, eatt_support);
+ mService.registerClient(
+ new ParcelUuid(uuid), mBluetoothGattCallback, eatt_support, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -888,7 +894,7 @@
try {
mCallback = null;
- mService.unregisterClient(mClientIf);
+ mService.unregisterClient(mClientIf, mAttributionSource);
mClientIf = 0;
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -958,7 +964,7 @@
if (mService == null || mClientIf == 0) return;
try {
- mService.clientDisconnect(mClientIf, mDevice.getAddress());
+ mService.clientDisconnect(mClientIf, mDevice.getAddress(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -977,8 +983,9 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect() {
try {
+ // autoConnect is inverse of "isDirect"
mService.clientConnect(mClientIf, mDevice.getAddress(), false, mTransport,
- mOpportunistic, mPhy); // autoConnect is inverse of "isDirect"
+ mOpportunistic, mPhy, mAttributionSource);
return true;
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1009,7 +1016,7 @@
public void setPreferredPhy(int txPhy, int rxPhy, int phyOptions) {
try {
mService.clientSetPreferredPhy(mClientIf, mDevice.getAddress(), txPhy, rxPhy,
- phyOptions);
+ phyOptions, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1023,7 +1030,7 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void readPhy() {
try {
- mService.clientReadPhy(mClientIf, mDevice.getAddress());
+ mService.clientReadPhy(mClientIf, mDevice.getAddress(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1060,7 +1067,7 @@
mServices.clear();
try {
- mService.discoverServices(mClientIf, mDevice.getAddress());
+ mService.discoverServices(mClientIf, mDevice.getAddress(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -1087,7 +1094,8 @@
mServices.clear();
try {
- mService.discoverServiceByUuid(mClientIf, mDevice.getAddress(), new ParcelUuid(uuid));
+ mService.discoverServiceByUuid(
+ mClientIf, mDevice.getAddress(), new ParcelUuid(uuid), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -1179,7 +1187,7 @@
try {
mService.readCharacteristic(mClientIf, device.getAddress(),
- characteristic.getInstanceId(), AUTHENTICATION_NONE);
+ characteristic.getInstanceId(), AUTHENTICATION_NONE, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
mDeviceBusy = false;
@@ -1214,7 +1222,8 @@
try {
mService.readUsingCharacteristicUuid(mClientIf, mDevice.getAddress(),
- new ParcelUuid(uuid), startHandle, endHandle, AUTHENTICATION_NONE);
+ new ParcelUuid(uuid), startHandle, endHandle, AUTHENTICATION_NONE,
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
mDeviceBusy = false;
@@ -1262,7 +1271,7 @@
try {
mService.writeCharacteristic(mClientIf, device.getAddress(),
characteristic.getInstanceId(), characteristic.getWriteType(),
- AUTHENTICATION_NONE, characteristic.getValue());
+ AUTHENTICATION_NONE, characteristic.getValue(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
mDeviceBusy = false;
@@ -1305,7 +1314,7 @@
try {
mService.readDescriptor(mClientIf, device.getAddress(),
- descriptor.getInstanceId(), AUTHENTICATION_NONE);
+ descriptor.getInstanceId(), AUTHENTICATION_NONE, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
mDeviceBusy = false;
@@ -1347,7 +1356,7 @@
try {
mService.writeDescriptor(mClientIf, device.getAddress(), descriptor.getInstanceId(),
- AUTHENTICATION_NONE, descriptor.getValue());
+ AUTHENTICATION_NONE, descriptor.getValue(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
mDeviceBusy = false;
@@ -1383,7 +1392,7 @@
if (mService == null || mClientIf == 0) return false;
try {
- mService.beginReliableWrite(mClientIf, mDevice.getAddress());
+ mService.beginReliableWrite(mClientIf, mDevice.getAddress(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -1416,7 +1425,7 @@
}
try {
- mService.endReliableWrite(mClientIf, mDevice.getAddress(), true);
+ mService.endReliableWrite(mClientIf, mDevice.getAddress(), true, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
mDeviceBusy = false;
@@ -1440,7 +1449,7 @@
if (mService == null || mClientIf == 0) return;
try {
- mService.endReliableWrite(mClientIf, mDevice.getAddress(), false);
+ mService.endReliableWrite(mClientIf, mDevice.getAddress(), false, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1487,7 +1496,7 @@
try {
mService.registerForNotification(mClientIf, device.getAddress(),
- characteristic.getInstanceId(), enable);
+ characteristic.getInstanceId(), enable, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -1510,7 +1519,7 @@
if (mService == null || mClientIf == 0) return false;
try {
- mService.refreshDevice(mClientIf, mDevice.getAddress());
+ mService.refreshDevice(mClientIf, mDevice.getAddress(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -1535,7 +1544,7 @@
if (mService == null || mClientIf == 0) return false;
try {
- mService.readRemoteRssi(mClientIf, mDevice.getAddress());
+ mService.readRemoteRssi(mClientIf, mDevice.getAddress(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -1567,7 +1576,7 @@
if (mService == null || mClientIf == 0) return false;
try {
- mService.configureMTU(mClientIf, mDevice.getAddress(), mtu);
+ mService.configureMTU(mClientIf, mDevice.getAddress(), mtu, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -1599,7 +1608,8 @@
if (mService == null || mClientIf == 0) return false;
try {
- mService.connectionParameterUpdate(mClientIf, mDevice.getAddress(), connectionPriority);
+ mService.connectionParameterUpdate(
+ mClientIf, mDevice.getAddress(), connectionPriority, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -1633,9 +1643,10 @@
try {
mService.leConnectionUpdate(mClientIf, mDevice.getAddress(),
- minConnectionInterval, maxConnectionInterval,
- slaveLatency, supervisionTimeout,
- minConnectionEventLen, maxConnectionEventLen);
+ minConnectionInterval, maxConnectionInterval,
+ slaveLatency, supervisionTimeout,
+ minConnectionEventLen, maxConnectionEventLen,
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 865f476..3e799de 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -21,6 +21,7 @@
import android.annotation.SuppressLint;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
+import android.content.AttributionSource;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.util.Log;
@@ -45,8 +46,10 @@
private static final boolean DBG = true;
private static final boolean VDBG = false;
- private BluetoothAdapter mAdapter;
- private IBluetoothGatt mService;
+ private final IBluetoothGatt mService;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
+
private BluetoothGattServerCallback mCallback;
private Object mServerIfLock = new Object();
@@ -382,9 +385,11 @@
/**
* Create a BluetoothGattServer proxy object.
*/
- /*package*/ BluetoothGattServer(IBluetoothGatt iGatt, int transport) {
+ /* package */ BluetoothGattServer(IBluetoothGatt iGatt, int transport,
+ BluetoothAdapter adapter) {
mService = iGatt;
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
mCallback = null;
mServerIf = 0;
mTransport = transport;
@@ -488,7 +493,8 @@
mCallback = callback;
try {
- mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback, eatt_support);
+ mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback,
+ eatt_support, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
mCallback = null;
@@ -522,7 +528,7 @@
try {
mCallback = null;
- mService.unregisterServer(mServerIf);
+ mService.unregisterServer(mServerIf, mAttributionSource);
mServerIf = 0;
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -576,7 +582,8 @@
try {
// autoConnect is inverse of "isDirect"
- mService.serverConnect(mServerIf, device.getAddress(), !autoConnect, mTransport);
+ mService.serverConnect(
+ mServerIf, device.getAddress(), !autoConnect, mTransport, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -599,7 +606,7 @@
if (mService == null || mServerIf == 0) return;
try {
- mService.serverDisconnect(mServerIf, device.getAddress());
+ mService.serverDisconnect(mServerIf, device.getAddress(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -628,7 +635,7 @@
public void setPreferredPhy(BluetoothDevice device, int txPhy, int rxPhy, int phyOptions) {
try {
mService.serverSetPreferredPhy(mServerIf, device.getAddress(), txPhy, rxPhy,
- phyOptions);
+ phyOptions, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -644,7 +651,7 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void readPhy(BluetoothDevice device) {
try {
- mService.serverReadPhy(mServerIf, device.getAddress());
+ mService.serverReadPhy(mServerIf, device.getAddress(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -679,7 +686,7 @@
try {
mService.sendResponse(mServerIf, device.getAddress(), requestId,
- status, offset, value);
+ status, offset, value, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -722,7 +729,7 @@
try {
mService.sendNotification(mServerIf, device.getAddress(),
characteristic.getInstanceId(), confirm,
- characteristic.getValue());
+ characteristic.getValue(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -757,7 +764,7 @@
mPendingService = service;
try {
- mService.addService(mServerIf, service);
+ mService.addService(mServerIf, service, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -784,7 +791,7 @@
if (intService == null) return false;
try {
- mService.removeService(mServerIf, service.getInstanceId());
+ mService.removeService(mServerIf, service.getInstanceId(), mAttributionSource);
mServices.remove(intService);
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -805,7 +812,7 @@
if (mService == null || mServerIf == 0) return;
try {
- mService.clearServices(mServerIf);
+ mService.clearServices(mServerIf, mAttributionSource);
mServices.clear();
} catch (RemoteException e) {
Log.e(TAG, "", e);
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 51ef3c2..9dc2d8e 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -28,6 +28,7 @@
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
import android.content.ComponentName;
import android.content.Context;
import android.os.Binder;
@@ -339,7 +340,8 @@
private Context mContext;
private ServiceListener mServiceListener;
private volatile IBluetoothHeadset mService;
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
@SuppressLint("AndroidFrameworkBluetoothPermission")
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
@@ -357,10 +359,11 @@
/**
* Create a BluetoothHeadset proxy object.
*/
- /*package*/ BluetoothHeadset(Context context, ServiceListener l) {
+ /* package */ BluetoothHeadset(Context context, ServiceListener l, BluetoothAdapter adapter) {
mContext = context;
mServiceListener = l;
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if (mgr != null) {
@@ -519,7 +522,8 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -540,7 +544,9 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -603,7 +609,8 @@
}
try {
return service.setPriority(
- device, BluetoothAdapter.priorityToConnectionPolicy(priority));
+ device, BluetoothAdapter.priorityToConnectionPolicy(priority),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -642,7 +649,7 @@
return false;
}
try {
- return service.setConnectionPolicy(device, connectionPolicy);
+ return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -672,7 +679,8 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return BluetoothAdapter.connectionPolicyToPriority(service.getPriority(device));
+ return BluetoothAdapter.connectionPolicyToPriority(
+ service.getPriority(device, mAttributionSource));
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return BluetoothProfile.PRIORITY_OFF;
@@ -694,13 +702,17 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
final IBluetoothHeadset service = mService;
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionPolicy(device);
+ return service.getConnectionPolicy(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
@@ -724,7 +736,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.isNoiseReductionSupported(device);
+ return service.isNoiseReductionSupported(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -747,7 +759,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.isVoiceRecognitionSupported(device);
+ return service.isVoiceRecognitionSupported(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -786,7 +798,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.startVoiceRecognition(device);
+ return service.startVoiceRecognition(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -815,7 +827,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.stopVoiceRecognition(device);
+ return service.stopVoiceRecognition(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -838,7 +850,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.isAudioConnected(device);
+ return service.isAudioConnected(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -872,7 +884,7 @@
final IBluetoothHeadset service = mService;
if (service != null && !isDisabled()) {
try {
- return service.getAudioState(device);
+ return service.getAudioState(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -900,7 +912,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- service.setAudioRouteAllowed(allowed);
+ service.setAudioRouteAllowed(allowed, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -923,7 +935,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- return service.getAudioRouteAllowed();
+ return service.getAudioRouteAllowed(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -948,7 +960,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- service.setForceScoAudio(forced);
+ service.setForceScoAudio(forced, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -973,7 +985,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- return service.isAudioOn();
+ return service.isAudioOn(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -1008,7 +1020,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- return service.connectAudio();
+ return service.connectAudio(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -1037,7 +1049,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- return service.disconnectAudio();
+ return service.disconnectAudio(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -1081,7 +1093,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- return service.startScoUsingVirtualVoiceCall();
+ return service.startScoUsingVirtualVoiceCall(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -1116,7 +1128,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- return service.stopScoUsingVirtualVoiceCall();
+ return service.stopScoUsingVirtualVoiceCall(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -1146,7 +1158,8 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- service.phoneStateChanged(numActive, numHeld, callState, number, type, name);
+ service.phoneStateChanged(numActive, numHeld, callState, number, type, name,
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -1171,7 +1184,8 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- service.clccResponse(index, direction, status, mode, mpty, number, type);
+ service.clccResponse(index, direction, status, mode, mpty, number, type,
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -1211,7 +1225,8 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.sendVendorSpecificResultCode(device, command, arg);
+ return service.sendVendorSpecificResultCode(device, command, arg,
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -1255,7 +1270,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled() && (device == null || isValidDevice(device))) {
try {
- return service.setActiveDevice(device);
+ return service.setActiveDevice(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -1285,7 +1300,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- return service.getActiveDevice();
+ return service.getActiveDevice(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -1313,7 +1328,7 @@
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- return service.isInbandRingingEnabled();
+ return service.isInbandRingingEnabled(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index 840b4d3..0059cdb 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -23,6 +23,7 @@
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
import android.content.Context;
import android.os.Binder;
import android.os.Build;
@@ -424,7 +425,8 @@
public static final int CALL_ACCEPT_HOLD = 1;
public static final int CALL_ACCEPT_TERMINATE = 2;
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothHeadsetClient> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.HEADSET_CLIENT,
"BluetoothHeadsetClient", IBluetoothHeadsetClient.class.getName()) {
@@ -437,8 +439,10 @@
/**
* Create a BluetoothHeadsetClient proxy object.
*/
- /*package*/ BluetoothHeadsetClient(Context context, ServiceListener listener) {
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ /* package */ BluetoothHeadsetClient(Context context, ServiceListener listener,
+ BluetoothAdapter adapter) {
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
mProfileConnector.connect(context, listener);
}
@@ -479,7 +483,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.connect(device);
+ return service.connect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -507,7 +511,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.disconnect(device);
+ return service.disconnect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -531,7 +535,8 @@
getService();
if (service != null && isEnabled()) {
try {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(mAttributionSource), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -557,7 +562,9 @@
getService();
if (service != null && isEnabled()) {
try {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -582,7 +589,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionState(device);
+ return service.getConnectionState(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return BluetoothProfile.STATE_DISCONNECTED;
@@ -635,7 +642,7 @@
return false;
}
try {
- return service.setConnectionPolicy(device, connectionPolicy);
+ return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -683,7 +690,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionPolicy(device);
+ return service.getConnectionPolicy(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
@@ -712,7 +719,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.startVoiceRecognition(device);
+ return service.startVoiceRecognition(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -739,7 +746,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.sendVendorAtCommand(device, vendorId, atCommand);
+ return service.sendVendorAtCommand(device, vendorId, atCommand, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -767,7 +774,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.stopVoiceRecognition(device);
+ return service.stopVoiceRecognition(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -790,7 +797,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getCurrentCalls(device);
+ return service.getCurrentCalls(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -813,7 +820,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getCurrentAgEvents(device);
+ return service.getCurrentAgEvents(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -840,7 +847,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.acceptCall(device, flag);
+ return service.acceptCall(device, flag, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -864,7 +871,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.holdCall(device);
+ return service.holdCall(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -893,7 +900,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.rejectCall(device);
+ return service.rejectCall(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -926,7 +933,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.terminateCall(device, call);
+ return service.terminateCall(device, call, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -957,7 +964,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.enterPrivateMode(device, index);
+ return service.enterPrivateMode(device, index, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -987,7 +994,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.explicitCallTransfer(device);
+ return service.explicitCallTransfer(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -1013,7 +1020,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.dial(device, number);
+ return service.dial(device, number, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -1040,7 +1047,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.sendDTMF(device, code);
+ return service.sendDTMF(device, code, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -1069,7 +1076,7 @@
getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getLastVoiceTagNumber(device);
+ return service.getLastVoiceTagNumber(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -1092,7 +1099,7 @@
getService();
if (service != null && isEnabled()) {
try {
- return service.getAudioState(device);
+ return service.getAudioState(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -1118,7 +1125,7 @@
getService();
if (service != null && isEnabled()) {
try {
- service.setAudioRouteAllowed(device, allowed);
+ service.setAudioRouteAllowed(device, allowed, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -1143,7 +1150,7 @@
getService();
if (service != null && isEnabled()) {
try {
- return service.getAudioRouteAllowed(device);
+ return service.getAudioRouteAllowed(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -1170,7 +1177,7 @@
getService();
if (service != null && isEnabled()) {
try {
- return service.connectAudio(device);
+ return service.connectAudio(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -1197,7 +1204,7 @@
getService();
if (service != null && isEnabled()) {
try {
- return service.disconnectAudio(device);
+ return service.disconnectAudio(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -1221,7 +1228,7 @@
getService();
if (service != null && isEnabled()) {
try {
- return service.getCurrentAgFeatures(device);
+ return service.getCurrentAgFeatures(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index fa52eda..3ff2ebd 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -28,6 +28,7 @@
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
import android.content.Context;
import android.os.Binder;
import android.os.Build;
@@ -130,7 +131,8 @@
*/
public static final long HI_SYNC_ID_INVALID = IBluetoothHearingAid.HI_SYNC_ID_INVALID;
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothHearingAid> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.HEARING_AID,
"BluetoothHearingAid", IBluetoothHearingAid.class.getName()) {
@@ -144,8 +146,10 @@
* Create a BluetoothHearingAid proxy object for interacting with the local
* Bluetooth Hearing Aid service.
*/
- /*package*/ BluetoothHearingAid(Context context, ServiceListener listener) {
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ /* package */ BluetoothHearingAid(Context context, ServiceListener listener,
+ BluetoothAdapter adapter) {
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
mProfileConnector.connect(context, listener);
}
@@ -181,7 +185,7 @@
final IBluetoothHearingAid service = getService();
try {
if (service != null && isEnabled() && isValidDevice(device)) {
- return service.connect(device);
+ return service.connect(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
@@ -213,13 +217,17 @@
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
final IBluetoothHearingAid service = getService();
try {
if (service != null && isEnabled() && isValidDevice(device)) {
- return service.disconnect(device);
+ return service.disconnect(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
@@ -240,7 +248,8 @@
final IBluetoothHearingAid service = getService();
try {
if (service != null && isEnabled()) {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(mAttributionSource), mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<BluetoothDevice>();
@@ -262,7 +271,9 @@
final IBluetoothHearingAid service = getService();
try {
if (service != null && isEnabled()) {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<BluetoothDevice>();
@@ -285,7 +296,7 @@
try {
if (service != null && isEnabled()
&& isValidDevice(device)) {
- return service.getConnectionState(device);
+ return service.getConnectionState(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return BluetoothProfile.STATE_DISCONNECTED;
@@ -324,7 +335,7 @@
try {
if (service != null && isEnabled()
&& ((device == null) || isValidDevice(device))) {
- service.setActiveDevice(device);
+ service.setActiveDevice(device, mAttributionSource);
return true;
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
@@ -352,7 +363,7 @@
final IBluetoothHearingAid service = getService();
try {
if (service != null && isEnabled()) {
- return service.getActiveDevices();
+ return service.getActiveDevices(mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<>();
@@ -413,7 +424,7 @@
&& connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
return false;
}
- return service.setConnectionPolicy(device, connectionPolicy);
+ return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
@@ -433,7 +444,11 @@
* @return priority of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
@@ -451,7 +466,11 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
verifyDeviceNotNull(device, "getConnectionPolicy");
@@ -459,7 +478,7 @@
try {
if (service != null && isEnabled()
&& isValidDevice(device)) {
- return service.getConnectionPolicy(device);
+ return service.getConnectionPolicy(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
@@ -511,7 +530,7 @@
if (!isEnabled()) return;
- service.setVolume(volume);
+ service.setVolume(volume, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
}
@@ -528,7 +547,11 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public long getHiSyncId(@NonNull BluetoothDevice device) {
if (VDBG) {
log("getHiSyncId(" + device + ")");
@@ -543,7 +566,7 @@
if (!isEnabled() || !isValidDevice(device)) return HI_SYNC_ID_INVALID;
- return service.getHiSyncId(device);
+ return service.getHiSyncId(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return HI_SYNC_ID_INVALID;
@@ -568,7 +591,7 @@
try {
if (service != null && isEnabled()
&& isValidDevice(device)) {
- return service.getDeviceSide(device);
+ return service.getDeviceSide(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return SIDE_LEFT;
@@ -596,7 +619,7 @@
try {
if (service != null && isEnabled()
&& isValidDevice(device)) {
- return service.getDeviceMode(device);
+ return service.getDeviceMode(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return MODE_MONAURAL;
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index 6565ec0..11e5711 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -25,6 +25,7 @@
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SystemApi;
+import android.content.AttributionSource;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -415,7 +416,8 @@
}
}
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothHidDevice> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.HID_DEVICE,
"BluetoothHidDevice", IBluetoothHidDevice.class.getName()) {
@@ -425,8 +427,9 @@
}
};
- BluetoothHidDevice(Context context, ServiceListener listener) {
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ BluetoothHidDevice(Context context, ServiceListener listener, BluetoothAdapter adapter) {
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
mProfileConnector.connect(context, listener);
}
@@ -446,7 +449,8 @@
final IBluetoothHidDevice service = getService();
if (service != null) {
try {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(mAttributionSource), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -465,7 +469,9 @@
final IBluetoothHidDevice service = getService();
if (service != null) {
try {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -484,7 +490,7 @@
final IBluetoothHidDevice service = getService();
if (service != null) {
try {
- return service.getConnectionState(device);
+ return service.getConnectionState(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -544,7 +550,7 @@
if (service != null) {
try {
CallbackWrapper cbw = new CallbackWrapper(executor, callback);
- result = service.registerApp(sdp, inQos, outQos, cbw);
+ result = service.registerApp(sdp, inQos, outQos, cbw, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -573,7 +579,7 @@
final IBluetoothHidDevice service = getService();
if (service != null) {
try {
- result = service.unregisterApp();
+ result = service.unregisterApp(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -600,7 +606,7 @@
final IBluetoothHidDevice service = getService();
if (service != null) {
try {
- result = service.sendReport(device, id, data);
+ result = service.sendReport(device, id, data, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -628,7 +634,7 @@
final IBluetoothHidDevice service = getService();
if (service != null) {
try {
- result = service.replyReport(device, type, id, data);
+ result = service.replyReport(device, type, id, data, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -654,7 +660,7 @@
final IBluetoothHidDevice service = getService();
if (service != null) {
try {
- result = service.reportError(device, error);
+ result = service.reportError(device, error, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -678,7 +684,7 @@
if (service != null) {
try {
- return service.getUserAppName();
+ return service.getUserAppName(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -705,7 +711,7 @@
final IBluetoothHidDevice service = getService();
if (service != null) {
try {
- result = service.connect(device);
+ result = service.connect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -731,7 +737,7 @@
final IBluetoothHidDevice service = getService();
if (service != null) {
try {
- result = service.disconnect(device);
+ result = service.disconnect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -776,7 +782,7 @@
&& connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
return false;
}
- return service.setConnectionPolicy(device, connectionPolicy);
+ return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java
index 68a9d37..0abe18c 100644
--- a/core/java/android/bluetooth/BluetoothHidHost.java
+++ b/core/java/android/bluetooth/BluetoothHidHost.java
@@ -26,6 +26,7 @@
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.content.AttributionSource;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -236,7 +237,8 @@
public static final String EXTRA_IDLE_TIME =
"android.bluetooth.BluetoothHidHost.extra.IDLE_TIME";
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothHidHost> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.HID_HOST,
"BluetoothHidHost", IBluetoothHidHost.class.getName()) {
@@ -250,8 +252,10 @@
* Create a BluetoothHidHost proxy object for interacting with the local
* Bluetooth Service which handles the InputDevice profile
*/
- /*package*/ BluetoothHidHost(Context context, ServiceListener listener) {
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ /* package */ BluetoothHidHost(Context context, ServiceListener listener,
+ BluetoothAdapter adapter) {
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
mProfileConnector.connect(context, listener);
}
@@ -280,13 +284,17 @@
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.connect(device);
+ return service.connect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -318,13 +326,17 @@
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.disconnect(device);
+ return service.disconnect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -348,7 +360,8 @@
final IBluetoothHidHost service = getService();
if (service != null && isEnabled()) {
try {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(mAttributionSource), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -371,7 +384,9 @@
final IBluetoothHidHost service = getService();
if (service != null && isEnabled()) {
try {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -398,7 +413,7 @@
final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionState(device);
+ return service.getConnectionState(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return BluetoothProfile.STATE_DISCONNECTED;
@@ -419,7 +434,11 @@
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -438,7 +457,11 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -452,7 +475,7 @@
return false;
}
try {
- return service.setConnectionPolicy(device, connectionPolicy);
+ return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -472,7 +495,11 @@
* @return priority of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
@@ -490,7 +517,11 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
if (device == null) {
@@ -499,7 +530,7 @@
final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionPolicy(device);
+ return service.getConnectionPolicy(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
@@ -532,7 +563,7 @@
final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.virtualUnplug(device);
+ return service.virtualUnplug(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -559,7 +590,7 @@
final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getProtocolMode(device);
+ return service.getProtocolMode(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -584,7 +615,7 @@
final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.setProtocolMode(device, protocolMode);
+ return service.setProtocolMode(device, protocolMode, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -616,7 +647,8 @@
final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getReport(device, reportType, reportId, bufferSize);
+ return service.getReport(device, reportType, reportId, bufferSize,
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -643,7 +675,7 @@
final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.setReport(device, reportType, report);
+ return service.setReport(device, reportType, report, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -669,7 +701,7 @@
final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.sendData(device, report);
+ return service.sendData(device, report, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -694,7 +726,7 @@
final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getIdleTime(device);
+ return service.getIdleTime(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -720,7 +752,7 @@
final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.setIdleTime(device, idleTime);
+ return service.setIdleTime(device, idleTime, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java
index 462c7b7..51bfd04 100644
--- a/core/java/android/bluetooth/BluetoothLeAudio.java
+++ b/core/java/android/bluetooth/BluetoothLeAudio.java
@@ -26,6 +26,7 @@
import android.annotation.SuppressLint;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
+import android.content.AttributionSource;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -101,7 +102,8 @@
*/
public static final int GROUP_ID_INVALID = IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID;
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothLeAudio> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.LE_AUDIO, "BluetoothLeAudio",
IBluetoothLeAudio.class.getName()) {
@@ -115,8 +117,10 @@
* Create a BluetoothLeAudio proxy object for interacting with the local
* Bluetooth LeAudio service.
*/
- /*package*/ BluetoothLeAudio(Context context, ServiceListener listener) {
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ /* package */ BluetoothLeAudio(Context context, ServiceListener listener,
+ BluetoothAdapter adapter) {
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
mProfileConnector.connect(context, listener);
mCloseGuard = new CloseGuard();
mCloseGuard.open("close");
@@ -162,7 +166,7 @@
try {
final IBluetoothLeAudio service = getService();
if (service != null && mAdapter.isEnabled() && isValidDevice(device)) {
- return service.connect(device);
+ return service.connect(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
@@ -202,7 +206,7 @@
try {
final IBluetoothLeAudio service = getService();
if (service != null && mAdapter.isEnabled() && isValidDevice(device)) {
- return service.disconnect(device);
+ return service.disconnect(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
@@ -223,7 +227,8 @@
try {
final IBluetoothLeAudio service = getService();
if (service != null && mAdapter.isEnabled()) {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(mAttributionSource), mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<BluetoothDevice>();
@@ -245,7 +250,9 @@
try {
final IBluetoothLeAudio service = getService();
if (service != null && mAdapter.isEnabled()) {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<BluetoothDevice>();
@@ -268,7 +275,7 @@
final IBluetoothLeAudio service = getService();
if (service != null && mAdapter.isEnabled()
&& isValidDevice(device)) {
- return service.getConnectionState(device);
+ return service.getConnectionState(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return BluetoothProfile.STATE_DISCONNECTED;
@@ -306,7 +313,7 @@
final IBluetoothLeAudio service = getService();
if (service != null && mAdapter.isEnabled()
&& ((device == null) || isValidDevice(device))) {
- service.setActiveDevice(device);
+ service.setActiveDevice(device, mAttributionSource);
return true;
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
@@ -332,7 +339,7 @@
try {
final IBluetoothLeAudio service = getService();
if (service != null && mAdapter.isEnabled()) {
- return service.getActiveDevices();
+ return service.getActiveDevices(mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<>();
@@ -357,7 +364,7 @@
try {
final IBluetoothLeAudio service = getService();
if (service != null && mAdapter.isEnabled()) {
- return service.getGroupId(device);
+ return service.getGroupId(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return GROUP_ID_INVALID;
@@ -395,7 +402,7 @@
&& connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
return false;
}
- return service.setConnectionPolicy(device, connectionPolicy);
+ return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
@@ -424,7 +431,7 @@
final IBluetoothLeAudio service = getService();
if (service != null && mAdapter.isEnabled()
&& isValidDevice(device)) {
- return service.getConnectionPolicy(device);
+ return service.getConnectionPolicy(device, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 69f9a79..b13ccaf 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -20,8 +20,11 @@
import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
+import android.app.ActivityThread;
+import android.app.AppGlobals;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
+import android.content.AttributionSource;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.RemoteException;
@@ -56,16 +59,41 @@
private static final String TAG = "BluetoothManager";
private static final boolean DBG = false;
+ private final AttributionSource mAttributionSource;
private final BluetoothAdapter mAdapter;
/**
* @hide
*/
public BluetoothManager(Context context) {
- mAdapter = BluetoothAdapter.createAdapter();
+ mAttributionSource = resolveAttributionSource(context);
+ mAdapter = BluetoothAdapter.createAdapter(mAttributionSource);
+ }
+
+ /** {@hide} */
+ public static AttributionSource resolveAttributionSource(Context context) {
+ AttributionSource res = null;
if (context != null) {
- mAdapter.setAttributionSource(context.getAttributionSource());
+ res = context.getAttributionSource();
}
+ if (res == null) {
+ res = ActivityThread.currentAttributionSource();
+ }
+ if (res == null) {
+ int uid = android.os.Process.myUid();
+ if (uid == android.os.Process.ROOT_UID) {
+ uid = android.os.Process.SYSTEM_UID;
+ }
+ try {
+ res = new AttributionSource(uid,
+ AppGlobals.getPackageManager().getPackagesForUid(uid)[0], null);
+ } catch (RemoteException ignored) {
+ }
+ }
+ if (res == null) {
+ throw new IllegalStateException("Failed to resolve AttributionSource");
+ }
+ return res;
}
/**
@@ -126,24 +154,9 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices(int profile) {
if (DBG) Log.d(TAG, "getConnectedDevices");
- if (profile != BluetoothProfile.GATT && profile != BluetoothProfile.GATT_SERVER) {
- throw new IllegalArgumentException("Profile not supported: " + profile);
- }
-
- List<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>();
-
- try {
- IBluetoothManager managerService = mAdapter.getBluetoothManager();
- IBluetoothGatt iGatt = managerService.getBluetoothGatt();
- if (iGatt == null) return connectedDevices;
-
- connectedDevices = iGatt.getDevicesMatchingConnectionStates(
- new int[]{BluetoothProfile.STATE_CONNECTED});
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
-
- return connectedDevices;
+ return getDevicesMatchingConnectionStates(profile, new int[] {
+ BluetoothProfile.STATE_CONNECTED
+ });
}
/**
@@ -180,7 +193,9 @@
IBluetoothManager managerService = mAdapter.getBluetoothManager();
IBluetoothGatt iGatt = managerService.getBluetoothGatt();
if (iGatt == null) return devices;
- devices = iGatt.getDevicesMatchingConnectionStates(states);
+ devices = BluetoothDevice.setAttributionSource(
+ iGatt.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -283,7 +298,8 @@
Log.e(TAG, "Fail to get GATT Server connection");
return null;
}
- BluetoothGattServer mGattServer = new BluetoothGattServer(iGatt, transport);
+ BluetoothGattServer mGattServer =
+ new BluetoothGattServer(iGatt, transport, mAdapter);
Boolean regStatus = mGattServer.registerCallback(callback, eatt_support);
return regStatus ? mGattServer : null;
} catch (RemoteException e) {
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index a025d9b..88505b5 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -26,6 +26,7 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
import android.content.Context;
import android.os.Binder;
import android.os.Build;
@@ -79,7 +80,8 @@
*/
public static final int RESULT_CANCELED = 2;
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothMap> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.MAP,
"BluetoothMap", IBluetoothMap.class.getName()) {
@@ -92,9 +94,11 @@
/**
* Create a BluetoothMap proxy object.
*/
- /*package*/ BluetoothMap(Context context, ServiceListener listener) {
+ /* package */ BluetoothMap(Context context, ServiceListener listener,
+ BluetoothAdapter adapter) {
if (DBG) Log.d(TAG, "Create BluetoothMap proxy object");
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
mProfileConnector.connect(context, listener);
mCloseGuard = new CloseGuard();
mCloseGuard.open("close");
@@ -140,7 +144,7 @@
final IBluetoothMap service = getService();
if (service != null) {
try {
- return service.getState();
+ return service.getState(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -166,7 +170,7 @@
final IBluetoothMap service = getService();
if (service != null) {
try {
- return service.getClient();
+ return service.getClient(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -191,7 +195,7 @@
final IBluetoothMap service = getService();
if (service != null) {
try {
- return service.isConnected(device);
+ return service.isConnected(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -230,7 +234,7 @@
final IBluetoothMap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.disconnect(device);
+ return service.disconnect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -281,7 +285,8 @@
final IBluetoothMap service = getService();
if (service != null && isEnabled()) {
try {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(mAttributionSource), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -305,7 +310,9 @@
final IBluetoothMap service = getService();
if (service != null && isEnabled()) {
try {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -329,7 +336,7 @@
final IBluetoothMap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionState(device);
+ return service.getConnectionState(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return BluetoothProfile.STATE_DISCONNECTED;
@@ -388,7 +395,7 @@
return false;
}
try {
- return service.setConnectionPolicy(device, connectionPolicy);
+ return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -440,7 +447,7 @@
final IBluetoothMap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionPolicy(device);
+ return service.getConnectionPolicy(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
@@ -455,13 +462,10 @@
}
private boolean isEnabled() {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
- log("Bluetooth is Not enabled");
- return false;
+ return mAdapter.isEnabled();
}
+
private static boolean isValidDevice(BluetoothDevice device) {
return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
}
-
}
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index d72081c..14804db 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -21,12 +21,12 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
import android.content.Context;
import android.net.Uri;
import android.os.Binder;
@@ -173,7 +173,8 @@
/** @hide */
public static final int DELETED = 3;
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothMapClient> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.MAP_CLIENT,
"BluetoothMapClient", IBluetoothMapClient.class.getName()) {
@@ -186,9 +187,11 @@
/**
* Create a BluetoothMapClient proxy object.
*/
- /*package*/ BluetoothMapClient(Context context, ServiceListener listener) {
+ /* package */ BluetoothMapClient(Context context, ServiceListener listener,
+ BluetoothAdapter adapter) {
if (DBG) Log.d(TAG, "Create BluetoothMapClient proxy object");
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
mProfileConnector.connect(context, listener);
}
@@ -220,7 +223,7 @@
final IBluetoothMapClient service = getService();
if (service != null) {
try {
- return service.isConnected(device);
+ return service.isConnected(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -247,7 +250,7 @@
final IBluetoothMapClient service = getService();
if (service != null) {
try {
- return service.connect(device);
+ return service.connect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -276,7 +279,7 @@
final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.disconnect(device);
+ return service.disconnect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
}
@@ -299,7 +302,8 @@
final IBluetoothMapClient service = getService();
if (service != null && isEnabled()) {
try {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(mAttributionSource), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return new ArrayList<>();
@@ -323,7 +327,9 @@
final IBluetoothMapClient service = getService();
if (service != null && isEnabled()) {
try {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return new ArrayList<>();
@@ -347,7 +353,7 @@
final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionState(device);
+ return service.getConnectionState(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return BluetoothProfile.STATE_DISCONNECTED;
@@ -405,7 +411,7 @@
return false;
}
try {
- return service.setConnectionPolicy(device, connectionPolicy);
+ return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -456,7 +462,7 @@
final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionPolicy(device);
+ return service.getConnectionPolicy(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
@@ -493,7 +499,7 @@
if (service != null && isEnabled() && isValidDevice(device)) {
try {
return service.sendMessage(device, contacts.toArray(new Uri[contacts.size()]),
- message, sentIntent, deliveredIntent);
+ message, sentIntent, deliveredIntent, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -527,7 +533,8 @@
final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.sendMessage(device, contacts, message, sentIntent, deliveredIntent);
+ return service.sendMessage(device, contacts, message, sentIntent, deliveredIntent,
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -553,7 +560,7 @@
final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getUnreadMessages(device);
+ return service.getUnreadMessages(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -576,7 +583,8 @@
final IBluetoothMapClient service = getService();
try {
return (service != null && isEnabled() && isValidDevice(device))
- && ((service.getSupportedFeatures(device) & UPLOADING_FEATURE_BITMASK) > 0);
+ && ((service.getSupportedFeatures(device, mAttributionSource)
+ & UPLOADING_FEATURE_BITMASK) > 0);
} catch (RemoteException e) {
Log.e(TAG, e.getMessage());
}
@@ -610,7 +618,7 @@
if (service != null && isEnabled() && isValidDevice(device) && handle != null &&
(status == READ || status == UNREAD || status == UNDELETED || status == DELETED)) {
try {
- return service.setMessageStatus(device, handle, status);
+ return service.setMessageStatus(device, handle, status, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -620,14 +628,10 @@
}
private boolean isEnabled() {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
- if (DBG) Log.d(TAG, "Bluetooth is Not enabled");
- return false;
+ return mAdapter.isEnabled();
}
private static boolean isValidDevice(BluetoothDevice device) {
return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
}
-
}
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index c41c9de..90c94de 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -22,11 +22,12 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
import android.content.Context;
import android.os.Binder;
import android.os.Build;
@@ -183,7 +184,8 @@
private final Context mContext;
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothPan> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.PAN,
"BluetoothPan", IBluetoothPan.class.getName()) {
@@ -201,8 +203,10 @@
* @hide
*/
@UnsupportedAppUsage
- /*package*/ BluetoothPan(Context context, ServiceListener listener) {
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ /* package */ BluetoothPan(Context context, ServiceListener listener,
+ BluetoothAdapter adapter) {
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
mContext = context;
mProfileConnector.connect(context, listener);
}
@@ -250,7 +254,7 @@
final IBluetoothPan service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.connect(device);
+ return service.connect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -290,7 +294,7 @@
final IBluetoothPan service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.disconnect(device);
+ return service.disconnect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
@@ -329,7 +333,7 @@
&& connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
return false;
}
- return service.setConnectionPolicy(device, connectionPolicy);
+ return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
@@ -355,7 +359,8 @@
final IBluetoothPan service = getService();
if (service != null && isEnabled()) {
try {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(mAttributionSource), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -381,7 +386,9 @@
final IBluetoothPan service = getService();
if (service != null && isEnabled()) {
try {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -397,13 +404,17 @@
*/
@SystemApi
@Override
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public int getConnectionState(@NonNull BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
final IBluetoothPan service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionState(device);
+ return service.getConnectionState(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return BluetoothProfile.STATE_DISCONNECTED;
@@ -432,7 +443,7 @@
final IBluetoothPan service = getService();
if (service != null && isEnabled()) {
try {
- service.setBluetoothTethering(value, pkgName, mContext.getAttributionTag());
+ service.setBluetoothTethering(value, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
}
@@ -453,7 +464,7 @@
final IBluetoothPan service = getService();
if (service != null && isEnabled()) {
try {
- return service.isTetheringOn();
+ return service.isTetheringOn(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
}
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index ef6fddf..2600029 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -25,6 +25,7 @@
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -98,7 +99,8 @@
private volatile IBluetoothPbap mService;
private final Context mContext;
private ServiceListener mServiceListener;
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
/** @hide */
public static final int RESULT_FAILURE = 0;
@@ -129,10 +131,11 @@
*
* @hide
*/
- public BluetoothPbap(Context context, ServiceListener l) {
+ public BluetoothPbap(Context context, ServiceListener l, BluetoothAdapter adapter) {
mContext = context;
mServiceListener = l;
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if (mgr != null) {
try {
@@ -229,7 +232,8 @@
return new ArrayList<BluetoothDevice>();
}
try {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(mAttributionSource), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -243,13 +247,17 @@
*/
@SystemApi
@Override
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) {
log("getConnectionState: device=" + device);
try {
final IBluetoothPbap service = mService;
if (service != null && isEnabled() && isValidDevice(device)) {
- return service.getConnectionState(device);
+ return service.getConnectionState(device, mAttributionSource);
}
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
@@ -277,7 +285,9 @@
return new ArrayList<BluetoothDevice>();
}
try {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -317,7 +327,7 @@
&& connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
return false;
}
- return service.setConnectionPolicy(device, connectionPolicy);
+ return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
@@ -345,7 +355,7 @@
return false;
}
try {
- service.disconnect(device);
+ service.disconnect(device, mAttributionSource);
return true;
} catch (RemoteException e) {
Log.e(TAG, e.toString());
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
index 7f48638..3ebd8fe 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -23,6 +23,7 @@
import android.annotation.SuppressLint;
import android.annotation.SdkConstant.SdkConstantType;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.content.AttributionSource;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -57,7 +58,8 @@
/** Connection canceled before completion. */
public static final int RESULT_CANCELED = 2;
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothPbapClient> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.PBAP_CLIENT,
"BluetoothPbapClient", IBluetoothPbapClient.class.getName()) {
@@ -70,11 +72,12 @@
/**
* Create a BluetoothPbapClient proxy object.
*/
- BluetoothPbapClient(Context context, ServiceListener listener) {
+ BluetoothPbapClient(Context context, ServiceListener listener, BluetoothAdapter adapter) {
if (DBG) {
Log.d(TAG, "Create BluetoothPbapClient proxy object");
}
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
mProfileConnector.connect(context, listener);
}
@@ -111,7 +114,11 @@
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean connect(BluetoothDevice device) {
if (DBG) {
log("connect(" + device + ") for PBAP Client.");
@@ -119,7 +126,7 @@
final IBluetoothPbapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.connect(device);
+ return service.connect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -139,7 +146,11 @@
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean disconnect(BluetoothDevice device) {
if (DBG) {
log("disconnect(" + device + ")" + new Exception());
@@ -147,7 +158,7 @@
final IBluetoothPbapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- service.disconnect(device);
+ service.disconnect(device, mAttributionSource);
return true;
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
@@ -176,7 +187,8 @@
final IBluetoothPbapClient service = getService();
if (service != null && isEnabled()) {
try {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(mAttributionSource), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -203,7 +215,9 @@
final IBluetoothPbapClient service = getService();
if (service != null && isEnabled()) {
try {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -230,7 +244,7 @@
final IBluetoothPbapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionState(device);
+ return service.getConnectionState(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return BluetoothProfile.STATE_DISCONNECTED;
@@ -247,12 +261,7 @@
}
private boolean isEnabled() {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) {
- return true;
- }
- log("Bluetooth is Not enabled");
- return false;
+ return mAdapter.isEnabled();
}
private static boolean isValidDevice(BluetoothDevice device) {
@@ -270,7 +279,11 @@
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -288,7 +301,11 @@
* @return true if connectionPolicy is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) {
@@ -301,7 +318,7 @@
return false;
}
try {
- return service.setConnectionPolicy(device, connectionPolicy);
+ return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -323,7 +340,11 @@
* @return priority of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
@@ -340,7 +361,11 @@
* @return connection policy of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) {
log("getConnectionPolicy(" + device + ")");
@@ -348,7 +373,7 @@
final IBluetoothPbapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionPolicy(device);
+ return service.getConnectionPolicy(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
index b86857f..0631abd 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -20,11 +20,11 @@
import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
-import android.annotation.SuppressLint;
import android.annotation.SdkConstant.SdkConstantType;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
import android.content.Context;
import android.os.Binder;
import android.os.Build;
@@ -97,7 +97,8 @@
*/
public static final int RESULT_CANCELED = 2;
- private BluetoothAdapter mAdapter;
+ private final BluetoothAdapter mAdapter;
+ private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothSap> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.SAP,
"BluetoothSap", IBluetoothSap.class.getName()) {
@@ -110,9 +111,11 @@
/**
* Create a BluetoothSap proxy object.
*/
- /*package*/ BluetoothSap(Context context, ServiceListener listener) {
+ /* package */ BluetoothSap(Context context, ServiceListener listener,
+ BluetoothAdapter adapter) {
if (DBG) Log.d(TAG, "Create BluetoothSap proxy object");
- mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mAdapter = adapter;
+ mAttributionSource = adapter.getAttributionSource();
mProfileConnector.connect(context, listener);
}
@@ -154,7 +157,7 @@
final IBluetoothSap service = getService();
if (service != null) {
try {
- return service.getState();
+ return service.getState(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -179,7 +182,7 @@
final IBluetoothSap service = getService();
if (service != null) {
try {
- return service.getClient();
+ return service.getClient(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -204,7 +207,7 @@
final IBluetoothSap service = getService();
if (service != null) {
try {
- return service.isConnected(device);
+ return service.isConnected(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -242,7 +245,7 @@
final IBluetoothSap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.disconnect(device);
+ return service.disconnect(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -265,7 +268,8 @@
final IBluetoothSap service = getService();
if (service != null && isEnabled()) {
try {
- return service.getConnectedDevices();
+ return BluetoothDevice.setAttributionSource(
+ service.getConnectedDevices(mAttributionSource), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -288,7 +292,9 @@
final IBluetoothSap service = getService();
if (service != null && isEnabled()) {
try {
- return service.getDevicesMatchingConnectionStates(states);
+ return BluetoothDevice.setAttributionSource(
+ service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
@@ -311,7 +317,7 @@
final IBluetoothSap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionState(device);
+ return service.getConnectionState(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return BluetoothProfile.STATE_DISCONNECTED;
@@ -369,7 +375,7 @@
return false;
}
try {
- return service.setConnectionPolicy(device, connectionPolicy);
+ return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return false;
@@ -420,7 +426,7 @@
final IBluetoothSap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
- return service.getConnectionPolicy(device);
+ return service.getConnectionPolicy(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
@@ -435,17 +441,10 @@
}
private boolean isEnabled() {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-
- if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) {
- return true;
- }
- log("Bluetooth is Not enabled");
- return false;
+ return mAdapter.isEnabled();
}
private static boolean isValidDevice(BluetoothDevice device) {
return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
}
-
}
diff --git a/core/java/android/bluetooth/le/AdvertisingSet.java b/core/java/android/bluetooth/le/AdvertisingSet.java
index d7e48ca..caa91fb 100644
--- a/core/java/android/bluetooth/le/AdvertisingSet.java
+++ b/core/java/android/bluetooth/le/AdvertisingSet.java
@@ -18,12 +18,12 @@
import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManager;
import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.content.AttributionSource;
import android.os.RemoteException;
import android.util.Log;
@@ -40,11 +40,12 @@
private final IBluetoothGatt mGatt;
private int mAdvertiserId;
+ private AttributionSource mAttributionSource;
- /* package */ AdvertisingSet(int advertiserId,
- IBluetoothManager bluetoothManager) {
+ /* package */ AdvertisingSet(int advertiserId, IBluetoothManager bluetoothManager,
+ AttributionSource attributionSource) {
mAdvertiserId = advertiserId;
-
+ mAttributionSource = attributionSource;
try {
mGatt = bluetoothManager.getBluetoothGatt();
} catch (RemoteException e) {
@@ -75,7 +76,7 @@
int maxExtendedAdvertisingEvents) {
try {
mGatt.enableAdvertisingSet(mAdvertiserId, enable, duration,
- maxExtendedAdvertisingEvents);
+ maxExtendedAdvertisingEvents, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "remote exception - ", e);
}
@@ -98,7 +99,7 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setAdvertisingData(AdvertiseData advertiseData) {
try {
- mGatt.setAdvertisingData(mAdvertiserId, advertiseData);
+ mGatt.setAdvertisingData(mAdvertiserId, advertiseData, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "remote exception - ", e);
}
@@ -118,7 +119,7 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setScanResponseData(AdvertiseData scanResponse) {
try {
- mGatt.setScanResponseData(mAdvertiserId, scanResponse);
+ mGatt.setScanResponseData(mAdvertiserId, scanResponse, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "remote exception - ", e);
}
@@ -136,7 +137,7 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setAdvertisingParameters(AdvertisingSetParameters parameters) {
try {
- mGatt.setAdvertisingParameters(mAdvertiserId, parameters);
+ mGatt.setAdvertisingParameters(mAdvertiserId, parameters, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "remote exception - ", e);
}
@@ -152,7 +153,7 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setPeriodicAdvertisingParameters(PeriodicAdvertisingParameters parameters) {
try {
- mGatt.setPeriodicAdvertisingParameters(mAdvertiserId, parameters);
+ mGatt.setPeriodicAdvertisingParameters(mAdvertiserId, parameters, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "remote exception - ", e);
}
@@ -173,7 +174,7 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setPeriodicAdvertisingData(AdvertiseData periodicData) {
try {
- mGatt.setPeriodicAdvertisingData(mAdvertiserId, periodicData);
+ mGatt.setPeriodicAdvertisingData(mAdvertiserId, periodicData, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "remote exception - ", e);
}
@@ -191,7 +192,7 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setPeriodicAdvertisingEnabled(boolean enable) {
try {
- mGatt.setPeriodicAdvertisingEnable(mAdvertiserId, enable);
+ mGatt.setPeriodicAdvertisingEnable(mAdvertiserId, enable, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "remote exception - ", e);
}
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index ff279d8..5802974 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -26,6 +26,7 @@
import android.bluetooth.IBluetoothManager;
import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.content.AttributionSource;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
@@ -35,6 +36,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
/**
* This class provides a way to perform Bluetooth LE advertise operations, such as starting and
@@ -58,9 +60,11 @@
private static final int FLAGS_FIELD_BYTES = 3;
private static final int MANUFACTURER_SPECIFIC_DATA_LENGTH = 2;
+ private final BluetoothAdapter mBluetoothAdapter;
private final IBluetoothManager mBluetoothManager;
+ private final AttributionSource mAttributionSource;
+
private final Handler mHandler;
- private BluetoothAdapter mBluetoothAdapter;
private final Map<AdvertiseCallback, AdvertisingSetCallback>
mLegacyAdvertisers = new HashMap<>();
private final Map<AdvertisingSetCallback, IAdvertisingSetCallback>
@@ -74,9 +78,10 @@
* @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management
* @hide
*/
- public BluetoothLeAdvertiser(IBluetoothManager bluetoothManager) {
- mBluetoothManager = bluetoothManager;
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ public BluetoothLeAdvertiser(BluetoothAdapter bluetoothAdapter) {
+ mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter);
+ mBluetoothManager = mBluetoothAdapter.getBluetoothManager();
+ mAttributionSource = mBluetoothAdapter.getAttributionSource();
mHandler = new Handler(Looper.getMainLooper());
}
@@ -453,7 +458,8 @@
try {
gatt.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
- periodicData, duration, maxExtendedAdvertisingEvents, wrapped);
+ periodicData, duration, maxExtendedAdvertisingEvents, wrapped,
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Failed to start advertising set - ", e);
postStartSetFailure(handler, callback,
@@ -482,7 +488,7 @@
IBluetoothGatt gatt;
try {
gatt = mBluetoothManager.getBluetoothGatt();
- gatt.stopAdvertisingSet(wrapped);
+ gatt.stopAdvertisingSet(wrapped, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Failed to stop advertising - ", e);
}
@@ -600,8 +606,8 @@
return;
}
- AdvertisingSet advertisingSet =
- new AdvertisingSet(advertiserId, mBluetoothManager);
+ AdvertisingSet advertisingSet = new AdvertisingSet(
+ advertiserId, mBluetoothManager, mAttributionSource);
mAdvertisingSets.put(advertiserId, advertisingSet);
callback.onAdvertisingSetStarted(advertisingSet, txPower, status);
}
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index f27f22b..60d4e2d 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -41,6 +41,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* This class provides methods to perform scan related operations for Bluetooth LE devices. An
@@ -80,12 +81,13 @@
*/
public static final String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE";
+ private final BluetoothAdapter mBluetoothAdapter;
private final IBluetoothManager mBluetoothManager;
- private final Handler mHandler;
- private BluetoothAdapter mBluetoothAdapter;
- private final Map<ScanCallback, BleScanCallbackWrapper> mLeScanClients;
private final AttributionSource mAttributionSource;
+ private final Handler mHandler;
+ private final Map<ScanCallback, BleScanCallbackWrapper> mLeScanClients;
+
/**
* Use {@link BluetoothAdapter#getBluetoothLeScanner()} instead.
*
@@ -94,13 +96,12 @@
* @param featureId The featureId of the context this object was created from
* @hide
*/
- public BluetoothLeScanner(IBluetoothManager bluetoothManager,
- @NonNull AttributionSource attributionSource) {
- mBluetoothManager = bluetoothManager;
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ public BluetoothLeScanner(BluetoothAdapter bluetoothAdapter) {
+ mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter);
+ mBluetoothManager = mBluetoothAdapter.getBluetoothManager();
+ mAttributionSource = mBluetoothAdapter.getAttributionSource();
mHandler = new Handler(Looper.getMainLooper());
mLeScanClients = new HashMap<ScanCallback, BleScanCallbackWrapper>();
- mAttributionSource = attributionSource;
}
/**
@@ -276,7 +277,8 @@
wrapper.startRegistration();
} else {
try {
- gatt.startScanForIntent(callbackIntent, settings, filters, mAttributionSource);
+ gatt.startScanForIntent(callbackIntent, settings, filters,
+ mAttributionSource);
} catch (RemoteException e) {
return ScanCallback.SCAN_FAILED_INTERNAL_ERROR;
}
@@ -321,7 +323,7 @@
IBluetoothGatt gatt;
try {
gatt = mBluetoothManager.getBluetoothGatt();
- gatt.stopScanForIntent(callbackIntent);
+ gatt.stopScanForIntent(callbackIntent, mAttributionSource);
} catch (RemoteException e) {
}
}
@@ -420,7 +422,7 @@
// Scan stopped.
if (mScannerId == -1 || mScannerId == -2) return;
try {
- mBluetoothGatt.registerScanner(this, mWorkSource);
+ mBluetoothGatt.registerScanner(this, mWorkSource, mAttributionSource);
wait(REGISTRATION_CALLBACK_TIMEOUT_MILLIS);
} catch (InterruptedException | RemoteException e) {
Log.e(TAG, "application registeration exception", e);
@@ -450,8 +452,8 @@
return;
}
try {
- mBluetoothGatt.stopScan(mScannerId);
- mBluetoothGatt.unregisterScanner(mScannerId);
+ mBluetoothGatt.stopScan(mScannerId, mAttributionSource);
+ mBluetoothGatt.unregisterScanner(mScannerId, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Failed to stop scan and unregister", e);
}
@@ -467,7 +469,7 @@
return;
}
try {
- mBluetoothGatt.flushPendingBatchResults(mScannerId);
+ mBluetoothGatt.flushPendingBatchResults(mScannerId, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Failed to get pending scan results", e);
}
@@ -486,7 +488,7 @@
try {
if (mScannerId == -1) {
// Registration succeeds after timeout, unregister scanner.
- mBluetoothGatt.unregisterScanner(scannerId);
+ mBluetoothGatt.unregisterScanner(scannerId, mAttributionSource);
} else {
mScannerId = scannerId;
mBluetoothGatt.startScan(mScannerId, mSettings, mFilters,
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
index 26978e3..47f47bb 100644
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
+++ b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
@@ -25,6 +25,7 @@
import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
import android.bluetooth.annotations.RequiresBluetoothScanPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.content.AttributionSource;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
@@ -32,6 +33,7 @@
import java.util.IdentityHashMap;
import java.util.Map;
+import java.util.Objects;
/**
* This class provides methods to perform periodic advertising related
@@ -54,8 +56,9 @@
private static final int SYNC_STARTING = -1;
+ private final BluetoothAdapter mBluetoothAdapter;
private final IBluetoothManager mBluetoothManager;
- private BluetoothAdapter mBluetoothAdapter;
+ private final AttributionSource mAttributionSource;
/* maps callback, to callback wrapper and sync handle */
Map<PeriodicAdvertisingCallback,
@@ -67,9 +70,10 @@
* @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management.
* @hide
*/
- public PeriodicAdvertisingManager(IBluetoothManager bluetoothManager) {
- mBluetoothManager = bluetoothManager;
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ public PeriodicAdvertisingManager(BluetoothAdapter bluetoothAdapter) {
+ mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter);
+ mBluetoothManager = mBluetoothAdapter.getBluetoothManager();
+ mAttributionSource = mBluetoothAdapter.getAttributionSource();
mCallbackWrappers = new IdentityHashMap<>();
}
@@ -166,7 +170,8 @@
mCallbackWrappers.put(callback, wrapped);
try {
- gatt.registerSync(scanResult, skip, timeout, wrapped);
+ gatt.registerSync(
+ scanResult, skip, timeout, wrapped, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Failed to register sync - ", e);
return;
@@ -202,7 +207,7 @@
}
try {
- gatt.unregisterSync(wrapper);
+ gatt.unregisterSync(wrapper, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Failed to cancel sync creation - ", e);
return;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 39933a9..b498325 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2189,6 +2189,8 @@
* Type: String
* </p>
*
+ * E.g. {@link android.Manifest.permission_group.CONTACTS}
+ *
* @hide
*/
@SystemApi
@@ -5339,6 +5341,8 @@
* A String[] holding attribution tags when used with
* {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
*
+ * E.g. an attribution tag could be location_provider, com.google.android.gms.*, etc.
+ *
* @hide
*/
@SystemApi
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 7fe2a41..5e72325 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -796,6 +796,10 @@
void setMimeGroup(String packageName, String group, in List<String> mimeTypes);
+ String getSplashScreenTheme(String packageName, int userId);
+
+ void setSplashScreenTheme(String packageName, String themeName, int userId);
+
List<String> getMimeGroup(String packageName, String group);
boolean isAutoRevokeWhitelisted(String packageName);
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 55a6ab7..84317b3 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -81,6 +81,7 @@
public int installReason;
public @PackageManager.UninstallReason int uninstallReason;
public String harmfulAppWarning;
+ public String splashScreenTheme;
public ArraySet<String> disabledComponents;
public ArraySet<String> enabledComponents;
@@ -130,6 +131,7 @@
if (o.componentLabelIconOverrideMap != null) {
this.componentLabelIconOverrideMap = new ArrayMap<>(o.componentLabelIconOverrideMap);
}
+ splashScreenTheme = o.splashScreenTheme;
}
@Nullable
@@ -242,6 +244,7 @@
return componentLabelIconOverrideMap.get(componentName);
}
+
/**
* Test if this package is installed.
*/
@@ -479,7 +482,11 @@
}
if (harmfulAppWarning == null && oldState.harmfulAppWarning != null
|| (harmfulAppWarning != null
- && !harmfulAppWarning.equals(oldState.harmfulAppWarning))) {
+ && !harmfulAppWarning.equals(oldState.harmfulAppWarning))) {
+ return false;
+ }
+
+ if (!Objects.equals(splashScreenTheme, oldState.splashScreenTheme)) {
return false;
}
return true;
@@ -505,6 +512,7 @@
hashCode = 31 * hashCode + Objects.hashCode(disabledComponents);
hashCode = 31 * hashCode + Objects.hashCode(enabledComponents);
hashCode = 31 * hashCode + Objects.hashCode(harmfulAppWarning);
+ hashCode = 31 * hashCode + Objects.hashCode(splashScreenTheme);
return hashCode;
}
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index d054ee2..948da3f 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -33,6 +33,7 @@
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.security.keystore.KeyProperties;
import android.util.Slog;
@@ -556,9 +557,22 @@
* @hide
*/
public long[] getAuthenticatorIds() {
+ return getAuthenticatorIds(UserHandle.getCallingUserId());
+ }
+
+ /**
+ * Get a list of AuthenticatorIDs for biometric authenticators which have 1) enrolled templates,
+ * and 2) meet the requirements for integrating with Keystore. The AuthenticatorIDs are known
+ * in Keystore land as SIDs, and are used during key generation.
+ *
+ * @param userId Android user ID for user to look up.
+ *
+ * @hide
+ */
+ public long[] getAuthenticatorIds(int userId) {
if (mService != null) {
try {
- return mService.getAuthenticatorIds();
+ return mService.getAuthenticatorIds(userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl
index 86df099..4c2a9ae 100644
--- a/core/java/android/hardware/biometrics/IAuthService.aidl
+++ b/core/java/android/hardware/biometrics/IAuthService.aidl
@@ -67,7 +67,9 @@
// Get a list of AuthenticatorIDs for authenticators which have enrolled templates and meet
// the requirements for integrating with Keystore. The AuthenticatorID are known in Keystore
// land as SIDs, and are used during key generation.
- long[] getAuthenticatorIds();
+ // If userId is not equal to the calling user ID, the caller must have the
+ // USE_BIOMETRIC_INTERNAL permission.
+ long[] getAuthenticatorIds(in int userId);
// See documentation in BiometricManager.
void resetLockoutTimeBound(IBinder token, String opPackageName, int fromSensorId, int userId,
diff --git a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
index 17b2abf..f365ee6 100644
--- a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
+++ b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
@@ -44,7 +44,7 @@
prop.resetLockoutRequiresHardwareAuthToken, prop.resetLockoutRequiresChallenge);
}
- protected SensorPropertiesInternal(int sensorId, @SensorProperties.Strength int sensorStrength,
+ public SensorPropertiesInternal(int sensorId, @SensorProperties.Strength int sensorStrength,
int maxEnrollmentsPerUser, @NonNull List<ComponentInfoInternal> componentInfo,
boolean resetLockoutRequiresHardwareAuthToken, boolean resetLockoutRequiresChallenge) {
this.sensorId = sensorId;
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index fd10c57..80b5078 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -73,6 +73,9 @@
* {@link CameraExtensionCharacteristics#getExtensionSupportedSizes(int, Class)} for supported
* repeating request output sizes.</p>
*
+ * <p>The extension characteristics for a given device are expected to remain static under
+ * normal operating conditions.</p>
+ *
* @see CameraManager#getCameraExtensionCharacteristics(String)
*/
public final class CameraExtensionCharacteristics {
@@ -585,7 +588,7 @@
* @throws IllegalArgumentException in case of format different from {@link ImageFormat#JPEG} /
* {@link ImageFormat#YUV_420_888}; or unsupported extension.
*/
- public @Nullable Range<Long> getEstimatedCaptureLatencyRange(@Extension int extension,
+ public @Nullable Range<Long> getEstimatedCaptureLatencyRangeMillis(@Extension int extension,
@NonNull Size captureOutputSize, @ImageFormat.Format int format) {
switch (format) {
case ImageFormat.YUV_420_888:
diff --git a/core/java/android/hardware/camera2/CameraInjectionSession.java b/core/java/android/hardware/camera2/CameraInjectionSession.java
new file mode 100644
index 0000000..bd5a4bc
--- /dev/null
+++ b/core/java/android/hardware/camera2/CameraInjectionSession.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * <p>The CameraInjectionSession class is what determines when injection is active.</p>
+ *
+ * <p>Your application must declare the
+ * {@link android.Manifest.permission#CAMERA_INJECT_EXTERNAL_CAMERA CAMERA} permission in its
+ * manifest in order to use camera injection function.</p>
+ *
+ * @hide
+ * @see CameraManager#injectCamera
+ * @see android.Manifest.permission#CAMERA_INJECT_EXTERNAL_CAMERA
+ */
+public abstract class CameraInjectionSession implements AutoCloseable {
+
+ /**
+ * Close the external camera and switch back to the internal camera.
+ *
+ * <p>Call the method when app streaming stops or the app exits, it switch back to the internal
+ * camera.</p>
+ */
+ @Override
+ public abstract void close();
+
+ /**
+ * A callback for external camera has a success or an error during injecting.
+ *
+ * <p>A callback instance must be provided to the {@link CameraManager#injectCamera} method to
+ * inject camera.</p>
+ *
+ * @hide
+ * @see CameraManager#injectCamera
+ */
+ public abstract static class InjectionStatusCallback {
+
+ /**
+ * An error code that can be reported by {@link #onInjectionError} indicating that the
+ * camera injection session has encountered a fatal error.
+ *
+ * @see #onInjectionError
+ */
+ public static final int ERROR_INJECTION_SESSION = 0;
+
+ /**
+ * An error code that can be reported by {@link #onInjectionError} indicating that the
+ * camera service has encountered a fatal error.
+ *
+ * <p>The Android device may need to be shut down and restarted to restore
+ * camera function, or there may be a persistent hardware problem.</p>
+ *
+ * <p>An attempt at recovery <i>may</i> be possible by closing the
+ * CameraDevice and the CameraManager, and trying to acquire all resources again from
+ * scratch.</p>
+ *
+ * @see #onInjectionError
+ */
+ public static final int ERROR_INJECTION_SERVICE = 1;
+
+ /**
+ * An error code that can be reported by {@link #onInjectionError} indicating that the
+ * injection camera does not support certain camera functions. When this error occurs, the
+ * default processing is still in the inject state, and the app is notified to display an
+ * error message and a black screen.
+ *
+ * @see #onInjectionError
+ */
+ public static final int ERROR_INJECTION_UNSUPPORTED = 2;
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"ERROR_"}, value =
+ {ERROR_INJECTION_SESSION,
+ ERROR_INJECTION_SERVICE,
+ ERROR_INJECTION_UNSUPPORTED})
+ public @interface ErrorCode {};
+
+ /**
+ * The method will be called when an external camera has been injected and replaced
+ * internal camera's feed.
+ *
+ * @param injectionSession The camera injection session that has been injected.
+ */
+ public abstract void onInjectionSucceeded(
+ @NonNull CameraInjectionSession injectionSession);
+
+ /**
+ * The method will be called when an error occurs in the injected external camera.
+ *
+ * @param errorCode The error code.
+ * @see #ERROR_INJECTION_SESSION
+ * @see #ERROR_INJECTION_SERVICE
+ * @see #ERROR_INJECTION_UNSUPPORTED
+ */
+ public abstract void onInjectionError(@NonNull int errorCode);
+ }
+
+ /**
+ * To be inherited by android.hardware.camera2.* code only.
+ *
+ * @hide
+ */
+ public CameraInjectionSession() {
+ }
+}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 651f025..2c5ec25 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -28,6 +28,7 @@
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
import android.hardware.camera2.impl.CameraDeviceImpl;
+import android.hardware.camera2.impl.CameraInjectionSessionImpl;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.params.ExtensionSessionConfiguration;
import android.hardware.camera2.params.SessionConfiguration;
@@ -1119,6 +1120,67 @@
}
/**
+ * Inject the external camera to replace the internal camera session.
+ *
+ * <p>If injecting the external camera device fails, then the injection callback's
+ * {@link CameraInjectionSession.InjectionStatusCallback#onInjectionError
+ * onInjectionError} method will be called.</p>
+ *
+ * @param packageName It scopes the injection to a particular app.
+ * @param internalCamId The id of one of the physical or logical cameras on the phone.
+ * @param externalCamId The id of one of the remote cameras that are provided by the dynamic
+ * camera HAL.
+ * @param executor The executor which will be used when invoking the callback.
+ * @param callback The callback which is invoked once the external camera is injected.
+ *
+ * @throws CameraAccessException If the camera device has been disconnected.
+ * {@link CameraAccessException#CAMERA_DISCONNECTED} will be
+ * thrown if camera service is not available.
+ * @throws SecurityException If the specific application that can cast to external
+ * devices does not have permission to inject the external
+ * camera.
+ * @throws IllegalArgumentException If cameraId doesn't match any currently or previously
+ * available camera device or some camera functions might not
+ * work properly or the injection camera runs into a fatal
+ * error.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.CAMERA_INJECT_EXTERNAL_CAMERA)
+ public void injectCamera(@NonNull String packageName, @NonNull String internalCamId,
+ @NonNull String externalCamId, @NonNull @CallbackExecutor Executor executor,
+ @NonNull CameraInjectionSession.InjectionStatusCallback callback)
+ throws CameraAccessException, SecurityException,
+ IllegalArgumentException {
+ if (CameraManagerGlobal.sCameraServiceDisabled) {
+ throw new IllegalArgumentException("No cameras available on device");
+ }
+ ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
+ if (cameraService == null) {
+ throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
+ "Camera service is currently unavailable");
+ }
+ synchronized (mLock) {
+ try {
+ CameraInjectionSessionImpl injectionSessionImpl =
+ new CameraInjectionSessionImpl(callback, executor);
+ ICameraInjectionCallback cameraInjectionCallback =
+ injectionSessionImpl.getCallback();
+ ICameraInjectionSession injectionSession = cameraService.injectCamera(packageName,
+ internalCamId, externalCamId, cameraInjectionCallback);
+ injectionSessionImpl.setRemoteInjectionSession(injectionSession);
+ } catch (ServiceSpecificException e) {
+ throwAsPublicException(e);
+ } catch (RemoteException e) {
+ // Camera service died - act as if it's a CAMERA_DISCONNECTED case
+ ServiceSpecificException sse = new ServiceSpecificException(
+ ICameraService.ERROR_DISCONNECTED,
+ "Camera service is currently unavailable");
+ throwAsPublicException(sse);
+ }
+ }
+ }
+
+ /**
* A per-process global camera manager instance, to retain a connection to the camera service,
* and to distribute camera availability notices to API-registered callbacks
*/
diff --git a/core/java/android/hardware/camera2/impl/CameraInjectionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraInjectionSessionImpl.java
new file mode 100644
index 0000000..231cc05
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/CameraInjectionSessionImpl.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.impl;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
+
+import android.hardware.camera2.CameraInjectionSession;
+import android.hardware.camera2.ICameraInjectionCallback;
+import android.hardware.camera2.ICameraInjectionSession;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.concurrent.Executor;
+
+
+/**
+ * The class inherits CameraInjectionSession. Use CameraManager#injectCamera to instantiate.
+ */
+public class CameraInjectionSessionImpl extends CameraInjectionSession
+ implements IBinder.DeathRecipient {
+ private static final String TAG = "CameraInjectionSessionImpl";
+
+ private final CameraInjectionCallback mCallback = new CameraInjectionCallback();
+ private final CameraInjectionSession.InjectionStatusCallback mInjectionStatusCallback;
+ private final Executor mExecutor;
+ private final Object mInterfaceLock = new Object();
+ private ICameraInjectionSession mInjectionSession;
+
+ public CameraInjectionSessionImpl(InjectionStatusCallback callback, Executor executor) {
+ mInjectionStatusCallback = callback;
+ mExecutor = executor;
+ }
+
+ @Override
+ public void close() {
+ synchronized (mInterfaceLock) {
+ try {
+ if (mInjectionSession != null) {
+ mInjectionSession.stopInjection();
+ mInjectionSession.asBinder().unlinkToDeath(this, /*flags*/0);
+ mInjectionSession = null;
+ }
+ } catch (RemoteException e) {
+ // Ignore binder errors for disconnect
+ }
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mInterfaceLock) {
+ Log.w(TAG, "CameraInjectionSessionImpl died unexpectedly");
+
+ if (mInjectionSession == null) {
+ return; // CameraInjectionSession already closed
+ }
+
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ mInjectionStatusCallback.onInjectionError(
+ CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_SERVICE);
+ }
+ };
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ CameraInjectionSessionImpl.this.mExecutor.execute(r);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ public CameraInjectionCallback getCallback() {
+ return mCallback;
+ }
+
+ /**
+ * Set remote injection session, which triggers initial onInjectionSucceeded callbacks.
+ *
+ * <p>This function may post onInjectionError if remoteInjectionSession dies
+ * during injecting.</p>
+ */
+ public void setRemoteInjectionSession(ICameraInjectionSession injectionSession) {
+ synchronized (mInterfaceLock) {
+ if (injectionSession == null) {
+ Log.e(TAG, "The camera injection session has encountered a serious error");
+ scheduleNotifyError(
+ CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_SESSION);
+ return;
+ }
+
+ mInjectionSession = injectionSession;
+
+ IBinder remoteSessionBinder = injectionSession.asBinder();
+ if (remoteSessionBinder == null) {
+ Log.e(TAG, "The camera injection session has encountered a serious error");
+ scheduleNotifyError(
+ CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_SESSION);
+ return;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ remoteSessionBinder.linkToDeath(this, /*flag*/ 0);
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mInjectionStatusCallback
+ .onInjectionSucceeded(CameraInjectionSessionImpl.this);
+ }
+ });
+ } catch (RemoteException e) {
+ scheduleNotifyError(
+ CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_SESSION);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ /**
+ * The method called when the injection camera has encountered a serious error.
+ *
+ * @param errorCode The error code.
+ * @see #ERROR_INJECTION_SESSION
+ * @see #ERROR_INJECTION_SERVICE
+ * @see #ERROR_INJECTION_UNSUPPORTED
+ */
+ public void onInjectionError(final int errorCode) {
+ Log.v(TAG, String.format(
+ "Injection session error received, code %d", errorCode));
+
+ synchronized (mInterfaceLock) {
+ if (mInjectionSession == null) {
+ return; // mInjectionSession already closed
+ }
+
+ switch (errorCode) {
+ case CameraInjectionCallback.ERROR_INJECTION_SESSION:
+ scheduleNotifyError(
+ CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_SESSION);
+ break;
+ case CameraInjectionCallback.ERROR_INJECTION_SERVICE:
+ scheduleNotifyError(
+ CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_SERVICE);
+ break;
+ case CameraInjectionCallback.ERROR_INJECTION_UNSUPPORTED:
+ scheduleNotifyError(
+ CameraInjectionSession.InjectionStatusCallback
+ .ERROR_INJECTION_UNSUPPORTED);
+ break;
+ default:
+ Log.e(TAG, "Unknown error from injection session: " + errorCode);
+ scheduleNotifyError(
+ CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_SERVICE);
+ }
+ }
+ }
+
+ private void scheduleNotifyError(final int errorCode) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(obtainRunnable(
+ CameraInjectionSessionImpl::notifyError,
+ this, errorCode).recycleOnUse());
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private void notifyError(final int errorCode) {
+ if (mInjectionSession != null) {
+ mInjectionStatusCallback.onInjectionError(errorCode);
+ }
+ }
+
+ /**
+ * The class inherits ICameraInjectionCallbacks.Stub. Use CameraManager#injectCamera to
+ * instantiate.
+ */
+ public class CameraInjectionCallback extends ICameraInjectionCallback.Stub {
+
+ @Override
+ public IBinder asBinder() {
+ return this;
+ }
+
+ @Override
+ public void onInjectionError(int errorCode) {
+ CameraInjectionSessionImpl.this.onInjectionError(errorCode);
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsConfig.aidl b/core/java/android/hardware/display/BrightnessInfo.aidl
similarity index 82%
rename from telephony/java/android/telephony/ims/RcsConfig.aidl
rename to core/java/android/hardware/display/BrightnessInfo.aidl
index cfd93fb..5da55c3 100644
--- a/telephony/java/android/telephony/ims/RcsConfig.aidl
+++ b/core/java/android/hardware/display/BrightnessInfo.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.telephony.ims;
+package android.hardware.display;
-parcelable RcsConfig;
+parcelable BrightnessInfo;
diff --git a/core/java/android/hardware/display/BrightnessInfo.java b/core/java/android/hardware/display/BrightnessInfo.java
new file mode 100644
index 0000000..4289860
--- /dev/null
+++ b/core/java/android/hardware/display/BrightnessInfo.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.display;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Data about the current brightness state.
+ * {@see android.view.Display.getBrightnessInfo()}
+ *
+ * @hide
+ */
+public final class BrightnessInfo implements Parcelable {
+
+ @IntDef(prefix = {"HIGH_BRIGHTNESS_MODE_"}, value = {
+ HIGH_BRIGHTNESS_MODE_OFF,
+ HIGH_BRIGHTNESS_MODE_SUNLIGHT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface HighBrightnessMode {}
+
+ /**
+ * High brightness mode is OFF. The high brightness range is not currently accessible to the
+ * user.
+ */
+ public static final int HIGH_BRIGHTNESS_MODE_OFF = 0;
+
+ /**
+ * High brightness mode is ON due to high ambient light (sunlight). The high brightness range is
+ * currently accessible to the user.
+ */
+ public static final int HIGH_BRIGHTNESS_MODE_SUNLIGHT = 1;
+
+ /** Brightness */
+ public final float brightness;
+
+ /** Current minimum supported brightness. */
+ public final float brightnessMinimum;
+
+ /** Current maximum supported brightness. */
+ public final float brightnessMaximum;
+
+ /**
+ * Current state of high brightness mode.
+ * Can be any of HIGH_BRIGHTNESS_MODE_* values.
+ */
+ public final int highBrightnessMode;
+
+ public BrightnessInfo(float brightness, float brightnessMinimum, float brightnessMaximum,
+ @HighBrightnessMode int highBrightnessMode) {
+ this.brightness = brightness;
+ this.brightnessMinimum = brightnessMinimum;
+ this.brightnessMaximum = brightnessMaximum;
+ this.highBrightnessMode = highBrightnessMode;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeFloat(brightness);
+ dest.writeFloat(brightnessMinimum);
+ dest.writeFloat(brightnessMaximum);
+ dest.writeInt(highBrightnessMode);
+ }
+
+ public static final @android.annotation.NonNull Creator<BrightnessInfo> CREATOR =
+ new Creator<BrightnessInfo>() {
+ @Override
+ public BrightnessInfo createFromParcel(Parcel source) {
+ return new BrightnessInfo(source);
+ }
+
+ @Override
+ public BrightnessInfo[] newArray(int size) {
+ return new BrightnessInfo[size];
+ }
+ };
+
+ private BrightnessInfo(Parcel source) {
+ brightness = source.readFloat();
+ brightnessMinimum = source.readFloat();
+ brightnessMaximum = source.readFloat();
+ highBrightnessMode = source.readInt();
+ }
+
+}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 6c2d140..de32adb1 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -418,6 +418,7 @@
EVENT_FLAG_DISPLAY_ADDED,
EVENT_FLAG_DISPLAY_CHANGED,
EVENT_FLAG_DISPLAY_REMOVED,
+ EVENT_FLAG_DISPLAY_BRIGHTNESS
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventsMask {}
@@ -449,6 +450,17 @@
*/
public static final long EVENT_FLAG_DISPLAY_CHANGED = 1L << 2;
+ /**
+ * Event flag to register for a display's brightness changes. This notification is sent
+ * through the {@link DisplayListener#onDisplayChanged} callback method. New brightness
+ * values can be retrieved via {@link android.view.Display#getBrightnessInfo()}.
+ *
+ * @see #registerDisplayListener(DisplayListener, Handler, long)
+ *
+ * @hide
+ */
+ public static final long EVENT_FLAG_DISPLAY_BRIGHTNESS = 1L << 3;
+
/** @hide */
public DisplayManager(Context context) {
mContext = context;
@@ -583,6 +595,7 @@
* @see #EVENT_FLAG_DISPLAY_ADDED
* @see #EVENT_FLAG_DISPLAY_CHANGED
* @see #EVENT_FLAG_DISPLAY_REMOVED
+ * @see #EVENT_FLAG_DISPLAY_BRIGHTNESS
* @see #registerDisplayListener(DisplayListener, Handler)
* @see #unregisterDisplayListener
*
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 983a43a..df51734 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -79,6 +79,7 @@
EVENT_DISPLAY_ADDED,
EVENT_DISPLAY_CHANGED,
EVENT_DISPLAY_REMOVED,
+ EVENT_DISPLAY_BRIGHTNESS_CHANGED
})
@Retention(RetentionPolicy.SOURCE)
public @interface DisplayEvent {}
@@ -86,6 +87,7 @@
public static final int EVENT_DISPLAY_ADDED = 1;
public static final int EVENT_DISPLAY_CHANGED = 2;
public static final int EVENT_DISPLAY_REMOVED = 3;
+ public static final int EVENT_DISPLAY_BRIGHTNESS_CHANGED = 4;
@UnsupportedAppUsage
private static DisplayManagerGlobal sInstance;
@@ -665,6 +667,17 @@
}
/**
+ * Retrieves Brightness Info for the specified display.
+ */
+ public BrightnessInfo getBrightnessInfo(int displayId) {
+ try {
+ return mDm.getBrightnessInfo(displayId);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Gets the preferred wide gamut color space for all displays.
* The wide gamut color space is returned from composition pipeline
* based on hardware capability.
@@ -934,6 +947,11 @@
}
}
break;
+ case EVENT_DISPLAY_BRIGHTNESS_CHANGED:
+ if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0) {
+ mListener.onDisplayChanged(msg.arg1);
+ }
+ break;
case EVENT_DISPLAY_REMOVED:
if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0) {
mListener.onDisplayRemoved(msg.arg1);
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 5ca4e0c..2303353 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -19,6 +19,7 @@
import android.content.pm.ParceledListSlice;
import android.graphics.Point;
import android.hardware.display.BrightnessConfiguration;
+import android.hardware.display.BrightnessInfo;
import android.hardware.display.Curve;
import android.hardware.display.IDisplayManagerCallback;
import android.hardware.display.IVirtualDisplayCallback;
@@ -143,6 +144,9 @@
// Get the minimum brightness curve.
Curve getMinimumBrightnessCurve();
+ // Get Brightness Information for the specified display.
+ BrightnessInfo getBrightnessInfo(int displayId);
+
// Gets the id of the preferred wide gamut color space for all displays.
// The wide gamut color space is returned from composition pipeline
// based on hardware capability.
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 13e2700..5f87899 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -133,11 +133,11 @@
}
@Override
- public void onFeatureGet(boolean success, int feature, boolean value) {
+ public void onFeatureGet(boolean success, int[] features, boolean[] featureState) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = success;
- args.argi1 = feature;
- args.arg2 = value;
+ args.arg2 = features;
+ args.arg3 = featureState;
mHandler.obtainMessage(MSG_GET_FEATURE_COMPLETED, args).sendToTarget();
}
@@ -1088,7 +1088,7 @@
* @hide
*/
public abstract static class GetFeatureCallback {
- public abstract void onCompleted(boolean success, int feature, boolean value);
+ public abstract void onCompleted(boolean success, int[] features, boolean[] featureState);
}
/**
@@ -1179,8 +1179,8 @@
case MSG_GET_FEATURE_COMPLETED:
SomeArgs args = (SomeArgs) msg.obj;
sendGetFeatureCompleted((boolean) args.arg1 /* success */,
- args.argi1 /* feature */,
- (boolean) args.arg2 /* value */);
+ (int[]) args.arg2 /* features */,
+ (boolean[]) args.arg3 /* featureState */);
args.recycle();
break;
case MSG_CHALLENGE_GENERATED:
@@ -1216,11 +1216,11 @@
mSetFeatureCallback.onCompleted(success, feature);
}
- private void sendGetFeatureCompleted(boolean success, int feature, boolean value) {
+ private void sendGetFeatureCompleted(boolean success, int[] features, boolean[] featureState) {
if (mGetFeatureCallback == null) {
return;
}
- mGetFeatureCallback.onCompleted(success, feature, value);
+ mGetFeatureCallback.onCompleted(success, features, featureState);
}
private void sendChallengeGenerated(int sensorId, long challenge) {
diff --git a/core/java/android/hardware/face/FaceServiceReceiver.java b/core/java/android/hardware/face/FaceServiceReceiver.java
index f0f975d..9e62ca5 100644
--- a/core/java/android/hardware/face/FaceServiceReceiver.java
+++ b/core/java/android/hardware/face/FaceServiceReceiver.java
@@ -66,7 +66,8 @@
}
@Override
- public void onFeatureGet(boolean success, int feature, boolean value) throws RemoteException {
+ public void onFeatureGet(boolean success, int[] features, boolean[] featureState)
+ throws RemoteException {
}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 0b44150..270d662 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -127,6 +127,8 @@
void getFeature(IBinder token, int userId, int feature, IFaceServiceReceiver receiver,
String opPackageName);
- // Give FaceService its ID. See AuthService.java
- void initializeConfiguration(int sensorId, int strength);
+ // Registers all HIDL and AIDL sensors. Only HIDL sensor properties need to be provided, because
+ // AIDL sensor properties are retrieved directly from the available HALs. If no HIDL HALs exist,
+ // hidlSensors must be non-null and empty. See AuthService.java
+ void registerAuthenticators(in List<FaceSensorPropertiesInternal> hidlSensors);
}
diff --git a/core/java/android/hardware/face/IFaceServiceReceiver.aidl b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
index 2ef1430..0ccb395 100644
--- a/core/java/android/hardware/face/IFaceServiceReceiver.aidl
+++ b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
@@ -32,7 +32,7 @@
void onError(int error, int vendorCode);
void onRemoved(in Face face, int remaining);
void onFeatureSet(boolean success, int feature);
- void onFeatureGet(boolean success, int feature, boolean value);
+ void onFeatureGet(boolean success, in int[] features, in boolean[] featureState);
void onChallengeGenerated(int sensorId, long challenge);
void onChallengeInterrupted(int sensorId);
void onChallengeInterruptFinished(int sensorId);
diff --git a/core/java/android/hardware/face/OWNERS b/core/java/android/hardware/face/OWNERS
index be10df1..0b4d9d9 100644
--- a/core/java/android/hardware/face/OWNERS
+++ b/core/java/android/hardware/face/OWNERS
@@ -1,7 +1,3 @@
# Bug component: 879035
-curtislb@google.com
-ilyamaty@google.com
-jaggies@google.com
-joshmccloskey@google.com
-kchyn@google.com
+include /services/core/java/com/android/server/biometrics/OWNERS
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 6a0772d..cc1aeeb 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -23,6 +23,7 @@
import static android.Manifest.permission.USE_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.Manifest.permission.USE_FINGERPRINT;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;
import static com.android.internal.util.FrameworkStatsLog.AUTH_DEPRECATED_APIUSED__DEPRECATED_API__API_FINGERPRINT_MANAGER_AUTHENTICATE;
import static com.android.internal.util.FrameworkStatsLog.AUTH_DEPRECATED_APIUSED__DEPRECATED_API__API_FINGERPRINT_MANAGER_HAS_ENROLLED_FINGERPRINTS;
@@ -878,6 +879,19 @@
}
/**
+ * Forwards FingerprintStateListener to FingerprintService
+ * @param listener new FingerprintStateListener being added
+ * @hide
+ */
+ public void registerFingerprintStateListener(@NonNull FingerprintStateListener listener) {
+ try {
+ mService.registerFingerprintStateListener(listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -989,6 +1003,41 @@
}
/**
+ * Returns whether the device has a power button fingerprint sensor.
+ * @return boolean indicating whether power button is fingerprint sensor
+ * @hide
+ */
+ public boolean isPowerbuttonFps() {
+ final FingerprintSensorPropertiesInternal sensorProps = getFirstFingerprintSensor();
+ return sensorProps.sensorType == TYPE_POWER_BUTTON;
+ }
+
+ /**
+ * Adds a callback that gets called when the service registers all of the fingerprint
+ * authenticators (HALs).
+ *
+ * If the fingerprint authenticators are already registered when the callback is added, the
+ * callback is invoked immediately.
+ *
+ * The callback is automatically removed after it's invoked.
+ *
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void addAuthenticatorsRegisteredCallback(
+ IFingerprintAuthenticatorsRegisteredCallback callback) {
+ if (mService != null) {
+ try {
+ mService.addAuthenticatorsRegisteredCallback(callback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "addProvidersAvailableCallback(): Service not connected!");
+ }
+ }
+
+ /**
* @hide
*/
public void addLockoutResetCallback(final LockoutResetCallback callback) {
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
index 58f6e62..4ffe5f1 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
@@ -20,7 +20,6 @@
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC;
import android.annotation.NonNull;
-import android.content.Context;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.SensorProperties;
import android.hardware.biometrics.SensorPropertiesInternal;
@@ -92,34 +91,6 @@
1636 /* sensorLocationY */, 130 /* sensorRadius */);
}
- /**
- * Initializes SensorProperties with specified values and values obtained from resources using
- * context.
- */
- // TODO(b/179175438): Remove this constructor once all HALs move to AIDL.
- public FingerprintSensorPropertiesInternal(@NonNull Context context, int sensorId,
- @SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
- @NonNull List<ComponentInfoInternal> componentInfo,
- @FingerprintSensorProperties.SensorType int sensorType,
- boolean resetLockoutRequiresHardwareAuthToken) {
- super(sensorId, strength, maxEnrollmentsPerUser, componentInfo,
- resetLockoutRequiresHardwareAuthToken, false /* resetLockoutRequiresChallenge */);
- this.sensorType = sensorType;
-
- int[] props = context.getResources().getIntArray(
- com.android.internal.R.array.config_udfps_sensor_props);
- if (props != null && props.length == 3) {
- this.sensorLocationX = props[0];
- this.sensorLocationY = props[1];
- this.sensorRadius = props[2];
- } else {
- // Fake coordinates that could be used for the fake UDFPS mode.
- this.sensorLocationX = 540;
- this.sensorLocationY = 1636;
- this.sensorRadius = 130;
- }
- }
-
protected FingerprintSensorPropertiesInternal(Parcel in) {
super(in);
sensorType = in.readInt();
diff --git a/core/java/android/hardware/fingerprint/IFingerprintAuthenticatorsRegisteredCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintAuthenticatorsRegisteredCallback.aidl
new file mode 100644
index 0000000..5a2c931
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/IFingerprintAuthenticatorsRegisteredCallback.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.fingerprint;
+
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import java.util.List;
+
+/**
+ * Callback to notify FingerprintManager that FingerprintService has registered all of the
+ * fingerprint authenticators (HALs).
+ * See {@link android.hardware.fingerprint.IFingerprintService#registerAuthenticators}.
+ *
+ * @hide
+ */
+oneway interface IFingerprintAuthenticatorsRegisteredCallback {
+ /**
+ * Notifies FingerprintManager that all of the fingerprint authenticators have been registered.
+ *
+ * @param sensors A consolidated list of sensor properties for all of the authenticators.
+ */
+ void onAllAuthenticatorsRegistered(in List<FingerprintSensorPropertiesInternal> sensors);
+}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 4bb3ab6..833747f 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -21,6 +21,7 @@
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
+import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.IFingerprintStateListener;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -144,8 +145,14 @@
// Removes a callback set by addClientActiveCallback
void removeClientActiveCallback(IFingerprintClientActiveCallback callback);
- // Give FingerprintService its ID. See AuthService.java
- void initializeConfiguration(int sensorId, int strength);
+ // Registers all HIDL and AIDL sensors. Only HIDL sensor properties need to be provided, because
+ // AIDL sensor properties are retrieved directly from the available HALs. If no HIDL HALs exist,
+ // hidlSensors must be non-null and empty. See AuthService.java
+ void registerAuthenticators(in List<FingerprintSensorPropertiesInternal> hidlSensors);
+
+ // Adds a callback which gets called when the service registers all of the fingerprint
+ // authenticators. The callback is automatically removed after it's invoked.
+ void addAuthenticatorsRegisteredCallback(IFingerprintAuthenticatorsRegisteredCallback callback);
// Notifies about a finger touching the sensor area.
void onPointerDown(int sensorId, int x, int y, float minor, float major);
@@ -156,6 +163,6 @@
// Sets the controller for managing the UDFPS overlay.
void setUdfpsOverlayController(in IUdfpsOverlayController controller);
- // Registers FingerprintStateListener in list stored by FingerprintService
+ // Registers FingerprintStateListener in list stored by FingerprintService.
void registerFingerprintStateListener(IFingerprintStateListener listener);
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl b/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl
index a4d34af..56dba7e 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@
/**
* Communication channel for FingerprintManager to register the FingerprintStateListener
- * in FingerprintService
+ * in FingerprintService.
* @hide
*/
oneway interface IFingerprintStateListener {
diff --git a/core/java/android/hardware/fingerprint/OWNERS b/core/java/android/hardware/fingerprint/OWNERS
index e55b8c56..5c93672 100644
--- a/core/java/android/hardware/fingerprint/OWNERS
+++ b/core/java/android/hardware/fingerprint/OWNERS
@@ -1,8 +1,3 @@
# Bug component: 114777
-curtislb@google.com
-ilyamaty@google.com
-jaggies@google.com
-joshmccloskey@google.com
-kchyn@google.com
-
+include /services/core/java/com/android/server/biometrics/OWNERS
diff --git a/core/java/android/hardware/iris/IIrisService.aidl b/core/java/android/hardware/iris/IIrisService.aidl
index 3d26318..98057d5 100644
--- a/core/java/android/hardware/iris/IIrisService.aidl
+++ b/core/java/android/hardware/iris/IIrisService.aidl
@@ -15,12 +15,16 @@
*/
package android.hardware.iris;
+import android.hardware.biometrics.SensorPropertiesInternal;
+
/**
* Communication channel from client to the iris service. These methods are all require the
* MANAGE_BIOMETRIC signature permission.
* @hide
*/
interface IIrisService {
- // Give IrisService its ID. See AuthService.java
- void initializeConfiguration(int sensorId, int strength);
+ // Registers all HIDL and AIDL sensors. Only HIDL sensor properties need to be provided, because
+ // AIDL sensor properties are retrieved directly from the available HALs. If no HIDL HALs exist,
+ // hidlSensors must be non-null and empty. See AuthService.java
+ void registerAuthenticators(in List<SensorPropertiesInternal> hidlSensors);
}
diff --git a/core/java/android/hardware/iris/OWNERS b/core/java/android/hardware/iris/OWNERS
index 33527f8..0b4d9d9 100644
--- a/core/java/android/hardware/iris/OWNERS
+++ b/core/java/android/hardware/iris/OWNERS
@@ -1,3 +1,3 @@
# Bug component: 879035
-jaggies@google.com
+include /services/core/java/com/android/server/biometrics/OWNERS
diff --git a/core/java/android/hardware/lights/Light.java b/core/java/android/hardware/lights/Light.java
index 7bfff5d..2c78fcb 100644
--- a/core/java/android/hardware/lights/Light.java
+++ b/core/java/android/hardware/lights/Light.java
@@ -37,20 +37,25 @@
/** Type for lights that indicate microphone usage */
public static final int LIGHT_TYPE_MICROPHONE = 8;
+ // These enum values start from 10001 to avoid collision with expanding of HAL light types.
/**
* Type for lights that indicate a monochrome color LED light.
*/
- public static final int LIGHT_TYPE_INPUT_SINGLE = 9;
+ public static final int LIGHT_TYPE_INPUT_SINGLE = 10001;
/**
* Type for lights that indicate a group of LED lights representing player ID.
+ * Player ID lights normally present on game controllers are lights that consist of a row of
+ * LEDs.
+ * During multi-player game, the player ID for the current game controller is represented by
+ * one of the LED that is lit according to its position in the row.
*/
- public static final int LIGHT_TYPE_INPUT_PLAYER_ID = 10;
+ public static final int LIGHT_TYPE_INPUT_PLAYER_ID = 10002;
/**
* Type for lights that indicate a color LED light.
*/
- public static final int LIGHT_TYPE_INPUT_RGB = 11;
+ public static final int LIGHT_TYPE_INPUT_RGB = 10003;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
diff --git a/core/java/android/hardware/lights/LightState.java b/core/java/android/hardware/lights/LightState.java
index 650b383..c6d7f63 100644
--- a/core/java/android/hardware/lights/LightState.java
+++ b/core/java/android/hardware/lights/LightState.java
@@ -18,6 +18,7 @@
import android.annotation.ColorInt;
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -65,27 +66,61 @@
}
/**
- * Creates a new LightState with the desired color and intensity, for a light type
- * of RBG color or single monochrome color.
- *
- * @param color the desired color and intensity in ARGB format.
- * @return The LightState object contains the color.
+ * Builder for creating device light change requests.
*/
- @NonNull
- public static LightState forColor(@ColorInt int color) {
- return new LightState(color, 0);
- }
+ public static final class Builder {
+ private int mValue;
+ private boolean mIsForPlayerId;
- /**
- * Creates a new LightState with the desired player id, for a light of type
- * {@link android.hardware.lights.Light#LIGHT_TYPE_INPUT_PLAYER_ID}.
- *
- * @param playerId the desired player id.
- * @return The LightState object contains the player id.
- */
- @NonNull
- public static LightState forPlayerId(int playerId) {
- return new LightState(0, playerId);
+ /** Creates a new {@link LightState.Builder}. */
+ public Builder() {
+ mValue = 0;
+ mIsForPlayerId = false;
+ }
+
+ /**
+ * Set the desired color and intensity of the LightState Builder, for a light type
+ * of RBG color or single monochrome color.
+ *
+ * @param color the desired color and intensity in ARGB format.
+ * @return The {@link LightState.Builder} object contains the light color and intensity.
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setColor(@ColorInt int color) {
+ mIsForPlayerId = false;
+ mValue = color;
+ return this;
+ }
+
+ /**
+ * Set the desired player id of the LightState Builder, for a light of type
+ * {@link android.hardware.lights.Light#LIGHT_TYPE_INPUT_PLAYER_ID}.
+ *
+ * @param playerId the desired player id.
+ * @return The {@link LightState.Builder} object contains the player id.
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setPlayerId(int playerId) {
+ mIsForPlayerId = true;
+ mValue = playerId;
+ return this;
+ }
+
+ /**
+ * Create a LightState object used to control lights on the device.
+ *
+ * <p>The generated {@link LightState} should be used in
+ * {@link LightsRequest.Builder#addLight(Light, LightState)}.
+ */
+ public @NonNull LightState build() {
+ if (!mIsForPlayerId) {
+ return new LightState(mValue, 0);
+ } else {
+ return new LightState(0, mValue);
+ }
+ }
}
/**
diff --git a/core/java/android/hardware/lights/LightsManager.java b/core/java/android/hardware/lights/LightsManager.java
index 8bc86da..cbcef86 100644
--- a/core/java/android/hardware/lights/LightsManager.java
+++ b/core/java/android/hardware/lights/LightsManager.java
@@ -99,6 +99,15 @@
/**
* Encapsulates a session that can be used to control device lights and represents the lifetime
* of the requests.
+ *
+ * <p>Any lights requests always live in a lights session which defines the lifecycle of the
+ * lights requests. A lights session is AutoCloseable that will get closed when leaving the
+ * session context.
+ *
+ * <p>Multiple sessions can make lights requests which contains same light. In the case the
+ * LightsManager implementation will arbitrate and honor one of the session's request. When
+ * the session hold the current light request closed, LightsManager implementation will choose
+ * another live session to honor its lights requests.
*/
public abstract static class LightsSession implements AutoCloseable {
private final IBinder mToken = new Binder();
diff --git a/core/java/android/hardware/lights/LightsRequest.java b/core/java/android/hardware/lights/LightsRequest.java
index 6fb0eb5..8d27dfd 100644
--- a/core/java/android/hardware/lights/LightsRequest.java
+++ b/core/java/android/hardware/lights/LightsRequest.java
@@ -24,7 +24,9 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Encapsulates a request to modify the state of multiple lights.
*
@@ -51,7 +53,7 @@
}
/**
- * Get a list of Light as ids. The ids will returned in same order as the lights passed
+ * Get a list of Light as ids. The ids will returned in same order as the lights passed
* in Builder.
*
* @return List of light ids
@@ -75,6 +77,18 @@
}
/**
+ * Get a map of light ids and states. The map will contain all the light ids as keys and
+ * the corresponding LightState requested as values.
+ */
+ public @NonNull Map<Integer, LightState> getLightsAndStates() {
+ Map<Integer, LightState> map = new HashMap<>();
+ for (int i = 0; i < mLightIds.length; i++) {
+ map.put(mLightIds[i], mLightStates[i]);
+ }
+ return map;
+ }
+
+ /**
* Builder for creating device light change requests.
*/
public static final class Builder {
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index 0766917..5a517ee 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -49,7 +49,6 @@
private static final int DO_UPDATE_CURSOR = 95;
private static final int DO_UPDATE_CURSOR_ANCHOR_INFO = 99;
private static final int DO_APP_PRIVATE_COMMAND = 100;
- private static final int DO_TOGGLE_SOFT_INPUT = 105;
private static final int DO_FINISH_SESSION = 110;
private static final int DO_VIEW_CLICKED = 115;
private static final int DO_NOTIFY_IME_HIDDEN = 120;
@@ -123,10 +122,6 @@
args.recycle();
return;
}
- case DO_TOGGLE_SOFT_INPUT: {
- mInputMethodSession.toggleSoftInput(msg.arg1, msg.arg2);
- return;
- }
case DO_FINISH_SESSION: {
doFinishSession();
return;
@@ -218,12 +213,6 @@
}
@Override
- public void toggleSoftInput(int showFlags, int hideFlags) {
- mCaller.executeOrSendMessage(
- mCaller.obtainMessageII(DO_TOGGLE_SOFT_INPUT, showFlags, hideFlags));
- }
-
- @Override
public void finishSession() {
mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_SESSION));
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 5267aa8..4defc55 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1042,8 +1042,14 @@
}
/**
- *
+ * Handles a request to toggle the IME visibility.
+ *
+ * @deprecated Starting in {@link Build.VERSION_CODES#S} the system no longer invokes this
+ * method, instead it explicitly shows or hides the IME. An {@code InputMethodService}
+ * wishing to toggle its own visibility should instead invoke {@link
+ * InputMethodService#requestShowSelf} or {@link InputMethodService#requestHideSelf}
*/
+ @Deprecated
public void toggleSoftInput(int showFlags, int hideFlags) {
InputMethodService.this.onToggleSoftInput(showFlags, hideFlags);
}
diff --git a/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java b/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
index 2db9ed1..f352f05 100644
--- a/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
+++ b/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
@@ -257,18 +257,6 @@
}
@Override
- public void toggleSoftInput(int showFlags, int hideFlags) {
- synchronized (mSessionLock) {
- if (mCallbackImpl == null || mHandler == null) {
- return;
- }
- mHandler.sendMessage(PooledLambda.obtainMessage(
- CallbackImpl::toggleSoftInput, mCallbackImpl, showFlags,
- hideFlags));
- }
- }
-
- @Override
public void finishSession() {
synchronized (mSessionLock) {
if (mCallbackImpl == null || mHandler == null) {
@@ -419,13 +407,6 @@
mOriginalCallback.onAppPrivateCommand(action, data);
}
- void toggleSoftInput(int showFlags, int hideFlags) {
- if (mFinished) {
- return;
- }
- mOriginalCallback.onToggleSoftInput(showFlags, hideFlags);
- }
-
void finishSession() {
if (mFinished) {
return;
diff --git a/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java b/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java
index 4b02085..0a23165 100644
--- a/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java
+++ b/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java
@@ -167,16 +167,6 @@
/**
* Called when the associated IME client called {@link
- * android.view.inputmethod.InputMethodManager#toggleSoftInput(int, int)}.
- *
- * @param showFlags The flag passed by the client.
- * @param hideFlags The flag passed by the client.
- * @see android.inputmethodservice.InputMethodService#onToggleSoftInput(int, int)
- */
- void onToggleSoftInput(int showFlags, int hideFlags);
-
- /**
- * Called when the associated IME client called {@link
* android.view.inputmethod.InputMethodManager#updateCursorAnchorInfo(View,
* CursorAnchorInfo)}.
*
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index c83dd99..d3c8957 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -82,6 +82,24 @@
public static final int MATCH_WIFI_WILDCARD = 7;
public static final int MATCH_BLUETOOTH = 8;
public static final int MATCH_PROXY = 9;
+ public static final int MATCH_CARRIER = 10;
+
+ /**
+ * Value of the match rule of the subscriberId to match networks with specific subscriberId.
+ */
+ public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0;
+ /**
+ * Value of the match rule of the subscriberId to match networks with any subscriberId which
+ * includes null and non-null.
+ */
+ public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1;
+
+ /**
+ * Wi-Fi Network ID is never supposed to be null (if it is, it is a bug that
+ * should be fixed), so it's not possible to want to match null vs
+ * non-null. Therefore it's fine to use null as a sentinel for Network ID.
+ */
+ public static final String WIFI_NETWORKID_ALL = null;
/**
* Include all network types when filtering. This is meant to merge in with the
@@ -125,6 +143,7 @@
case MATCH_WIFI_WILDCARD:
case MATCH_BLUETOOTH:
case MATCH_PROXY:
+ case MATCH_CARRIER:
return true;
default:
@@ -168,10 +187,12 @@
@NetworkType int ratType) {
if (TextUtils.isEmpty(subscriberId)) {
return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL);
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL);
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
/**
@@ -189,6 +210,8 @@
*/
@UnsupportedAppUsage
public static NetworkTemplate buildTemplateWifiWildcard() {
+ // TODO: Consider replace this with MATCH_WIFI with NETWORK_ID_ALL
+ // and SUBSCRIBER_ID_MATCH_RULE_ALL.
return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null);
}
@@ -202,8 +225,27 @@
* Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
* given SSID.
*/
- public static NetworkTemplate buildTemplateWifi(String networkId) {
- return new NetworkTemplate(MATCH_WIFI, null, networkId);
+ public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) {
+ Objects.requireNonNull(networkId);
+ return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */,
+ new String[] { null } /* matchSubscriberIds */,
+ networkId, METERED_ALL, ROAMING_ALL,
+ DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
+ SUBSCRIBER_ID_MATCH_RULE_ALL);
+ }
+
+ /**
+ * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID,
+ * and IMSI.
+ *
+ * Call with {@link #WIFI_NETWORKID_ALL} for {@code networkId} to get result regardless of SSID.
+ */
+ public static NetworkTemplate buildTemplateWifi(@Nullable String networkId,
+ @Nullable String subscriberId) {
+ return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId },
+ networkId, METERED_ALL, ROAMING_ALL,
+ DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
/**
@@ -231,6 +273,14 @@
return new NetworkTemplate(MATCH_PROXY, null, null);
}
+ /**
+ * Template to match all carrier networks with the given IMSI.
+ */
+ public static NetworkTemplate buildTemplateCarrier(@NonNull String subscriberId) {
+ Objects.requireNonNull(subscriberId);
+ return new NetworkTemplate(MATCH_CARRIER, subscriberId, null);
+ }
+
private final int mMatchRule;
private final String mSubscriberId;
@@ -251,10 +301,26 @@
private final int mRoaming;
private final int mDefaultNetwork;
private final int mSubType;
+ private final int mSubscriberIdMatchRule;
// Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}.
private final int mOemManaged;
+ private void checkValidSubscriberIdMatchRule() {
+ switch (mMatchRule) {
+ case MATCH_MOBILE:
+ case MATCH_CARRIER:
+ // MOBILE and CARRIER templates must always specify a subscriber ID.
+ if (mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) {
+ throw new IllegalArgumentException("Invalid SubscriberIdMatchRule"
+ + "on match rule: " + getMatchRuleName(mMatchRule));
+ }
+ return;
+ default:
+ return;
+ }
+ }
+
@UnsupportedAppUsage
public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
@@ -263,14 +329,25 @@
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
String networkId) {
this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL);
+ DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ }
+
+ // TODO: Remove it after updating all of the caller.
+ public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
+ String networkId, int metered, int roaming, int defaultNetwork, int subType,
+ int oemManaged) {
+ this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming,
+ defaultNetwork, subType, oemManaged, SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
String networkId, int metered, int roaming, int defaultNetwork, int subType,
- int oemManaged) {
+ int oemManaged, int subscriberIdMatchRule) {
mMatchRule = matchRule;
mSubscriberId = subscriberId;
+ // TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when
+ // mSubscriberId is null
mMatchSubscriberIds = matchSubscriberIds;
mNetworkId = networkId;
mMetered = metered;
@@ -278,7 +355,8 @@
mDefaultNetwork = defaultNetwork;
mSubType = subType;
mOemManaged = oemManaged;
-
+ mSubscriberIdMatchRule = subscriberIdMatchRule;
+ checkValidSubscriberIdMatchRule();
if (!isKnownMatchRule(matchRule)) {
Log.e(TAG, "Unknown network template rule " + matchRule
+ " will not match any identity.");
@@ -295,6 +373,7 @@
mDefaultNetwork = in.readInt();
mSubType = in.readInt();
mOemManaged = in.readInt();
+ mSubscriberIdMatchRule = in.readInt();
}
@Override
@@ -308,6 +387,7 @@
dest.writeInt(mDefaultNetwork);
dest.writeInt(mSubType);
dest.writeInt(mOemManaged);
+ dest.writeInt(mSubscriberIdMatchRule);
}
@Override
@@ -346,13 +426,15 @@
if (mOemManaged != OEM_MANAGED_ALL) {
builder.append(", oemManaged=").append(mOemManaged);
}
+ builder.append(", subscriberIdMatchRule=")
+ .append(subscriberIdMatchRuleToString(mSubscriberIdMatchRule));
return builder.toString();
}
@Override
public int hashCode() {
return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
- mDefaultNetwork, mSubType, mOemManaged);
+ mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule);
}
@Override
@@ -366,11 +448,23 @@
&& mRoaming == other.mRoaming
&& mDefaultNetwork == other.mDefaultNetwork
&& mSubType == other.mSubType
- && mOemManaged == other.mOemManaged;
+ && mOemManaged == other.mOemManaged
+ && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule;
}
return false;
}
+ private String subscriberIdMatchRuleToString(int rule) {
+ switch (rule) {
+ case SUBSCRIBER_ID_MATCH_RULE_EXACT:
+ return "EXACT_MATCH";
+ case SUBSCRIBER_ID_MATCH_RULE_ALL:
+ return "ALL";
+ default:
+ return "Unknown rule " + rule;
+ }
+ }
+
public boolean isMatchRuleMobile() {
switch (mMatchRule) {
case MATCH_MOBILE:
@@ -386,6 +480,14 @@
case MATCH_MOBILE_WILDCARD:
case MATCH_WIFI_WILDCARD:
return false;
+ case MATCH_CARRIER:
+ return mSubscriberId != null;
+ case MATCH_WIFI:
+ if (Objects.equals(mNetworkId, WIFI_NETWORKID_ALL)
+ && mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) {
+ return false;
+ }
+ return true;
default:
return true;
}
@@ -405,6 +507,10 @@
return mNetworkId;
}
+ public int getSubscriberIdMatchRule() {
+ return mSubscriberIdMatchRule;
+ }
+
/**
* Test if given {@link NetworkIdentity} matches this template.
*/
@@ -429,6 +535,8 @@
return matchesBluetooth(ident);
case MATCH_PROXY:
return matchesProxy(ident);
+ case MATCH_CARRIER:
+ return matchesCarrier(ident);
default:
// We have no idea what kind of network template we are, so we
// just claim not to match anything.
@@ -466,8 +574,23 @@
|| getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType);
}
- public boolean matchesSubscriberId(String subscriberId) {
- return ArrayUtils.contains(mMatchSubscriberIds, subscriberId);
+ /**
+ * Check if this template matches {@code subscriberId}. Returns true if this
+ * template was created with {@code SUBSCRIBER_ID_MATCH_RULE_ALL}, or with a
+ * {@code mMatchSubscriberIds} array that contains {@code subscriberId}.
+ */
+ public boolean matchesSubscriberId(@Nullable String subscriberId) {
+ return mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL
+ || ArrayUtils.contains(mMatchSubscriberIds, subscriberId);
+ }
+
+ /**
+ * Check if network with matching SSID. Returns true when the SSID matches, or when
+ * {@code mNetworkId} is {@code WIFI_NETWORKID_ALL}.
+ */
+ private boolean matchesWifiNetworkId(@Nullable String networkId) {
+ return Objects.equals(mNetworkId, WIFI_NETWORKID_ALL)
+ || Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId));
}
/**
@@ -566,8 +689,8 @@
private boolean matchesWifi(NetworkIdentity ident) {
switch (ident.mType) {
case TYPE_WIFI:
- return Objects.equals(
- sanitizeSsid(mNetworkId), sanitizeSsid(ident.mNetworkId));
+ return matchesSubscriberId(ident.mSubscriberId)
+ && matchesWifiNetworkId(ident.mNetworkId);
default:
return false;
}
@@ -583,6 +706,15 @@
return false;
}
+ /**
+ * Check if matches carrier network. The carrier networks means it includes the subscriberId.
+ */
+ private boolean matchesCarrier(NetworkIdentity ident) {
+ return ident.mSubscriberId != null
+ && !ArrayUtils.isEmpty(mMatchSubscriberIds)
+ && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
+ }
+
private boolean matchesMobileWildcard(NetworkIdentity ident) {
if (ident.mType == TYPE_WIMAX) {
return true;
@@ -635,6 +767,8 @@
return "BLUETOOTH";
case MATCH_PROXY:
return "PROXY";
+ case MATCH_CARRIER:
+ return "CARRIER";
default:
return "UNKNOWN(" + matchRule + ")";
}
diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java
index 77c8a4f..1927e20 100644
--- a/core/java/android/net/Proxy.java
+++ b/core/java/android/net/Proxy.java
@@ -60,6 +60,7 @@
* {@link ConnectivityManager#getDefaultProxy()} or
* {@link ConnectivityManager#getLinkProperties(Network)}.{@link LinkProperties#getHttpProxy()}
* to get the proxy for the Network(s) they are using.
+ * @removed
*/
@Deprecated
public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
diff --git a/core/java/android/net/TunnelConnectionParams.java b/core/java/android/net/TunnelConnectionParams.java
deleted file mode 100644
index f5b3539..0000000
--- a/core/java/android/net/TunnelConnectionParams.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-/**
- * TunnelConnectionParams represents a configuration to set up a tunnel connection.
- *
- * <p>Concrete implementations for a control plane protocol should implement this interface.
- * Subclasses should be immutable data classes containing connection, authentication and
- * authorization parameters required to establish a tunnel connection.
- *
- * @see android.net.ipsec.ike.IkeTunnelConnectionParams
- */
-// TODO:b/186071626 Remove TunnelConnectionParams when non-updatable API stub can resolve
-// IkeTunnelConnectionParams
-public interface TunnelConnectionParams {}
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 3c02cf0..eedeeb5 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -24,7 +24,7 @@
import android.annotation.SuppressLint;
import android.net.Network;
import android.net.NetworkCapabilities;
-import android.net.TunnelConnectionParams;
+import android.net.ipsec.ike.IkeTunnelConnectionParams;
import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtils;
import android.os.PersistableBundle;
import android.util.ArraySet;
@@ -159,7 +159,7 @@
@NonNull private final String mGatewayConnectionName;
private static final String TUNNEL_CONNECTION_PARAMS_KEY = "mTunnelConnectionParams";
- @NonNull private TunnelConnectionParams mTunnelConnectionParams;
+ @NonNull private IkeTunnelConnectionParams mTunnelConnectionParams;
private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities";
@NonNull private final SortedSet<Integer> mExposedCapabilities;
@@ -176,7 +176,7 @@
/** Builds a VcnGatewayConnectionConfig with the specified parameters. */
private VcnGatewayConnectionConfig(
@NonNull String gatewayConnectionName,
- @NonNull TunnelConnectionParams tunnelConnectionParams,
+ @NonNull IkeTunnelConnectionParams tunnelConnectionParams,
@NonNull Set<Integer> exposedCapabilities,
@NonNull Set<Integer> underlyingCapabilities,
@NonNull long[] retryIntervalsMs,
@@ -276,7 +276,7 @@
* @hide
*/
@NonNull
- public TunnelConnectionParams getTunnelConnectionParams() {
+ public IkeTunnelConnectionParams getTunnelConnectionParams() {
return mTunnelConnectionParams;
}
@@ -419,7 +419,7 @@
*/
public static final class Builder {
@NonNull private final String mGatewayConnectionName;
- @NonNull private final TunnelConnectionParams mTunnelConnectionParams;
+ @NonNull private final IkeTunnelConnectionParams mTunnelConnectionParams;
@NonNull private final Set<Integer> mExposedCapabilities = new ArraySet();
@NonNull private final Set<Integer> mUnderlyingCapabilities = new ArraySet();
@NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
@@ -437,13 +437,13 @@
* VcnConfig} must be given a unique name. This name is used by the caller to
* distinguish between VcnGatewayConnectionConfigs configured on a single {@link
* VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations.
- * @param tunnelConnectionParams the tunnel connection configuration
- * @see TunnelConnectionParams
+ * @param tunnelConnectionParams the IKE tunnel connection configuration
+ * @see IkeTunnelConnectionParams
* @see VcnManager.VcnStatusCallback#onGatewayConnectionError
*/
public Builder(
@NonNull String gatewayConnectionName,
- @NonNull TunnelConnectionParams tunnelConnectionParams) {
+ @NonNull IkeTunnelConnectionParams tunnelConnectionParams) {
Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null");
Objects.requireNonNull(tunnelConnectionParams, "tunnelConnectionParams was null");
diff --git a/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java
index 690e4e7..4bc5b49 100644
--- a/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java
+++ b/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java
@@ -16,7 +16,6 @@
package android.net.vcn.persistablebundleutils;
import android.annotation.NonNull;
-import android.net.TunnelConnectionParams;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.IkeTunnelConnectionParams;
import android.net.ipsec.ike.TunnelModeChildSessionParams;
@@ -25,7 +24,7 @@
import java.util.Objects;
/**
- * Utility class to convert TunnelConnectionParams to/from PersistableBundle
+ * Utility class to convert Tunnel Connection Params to/from PersistableBundle
*
* @hide
*/
@@ -34,30 +33,28 @@
private static final String PARAMS_TYPE_IKE = "IKE";
- /** Serializes an TunnelConnectionParams to a PersistableBundle. */
+ /** Serializes an IkeTunnelConnectionParams to a PersistableBundle. */
@NonNull
- public static PersistableBundle toPersistableBundle(@NonNull TunnelConnectionParams params) {
+ public static PersistableBundle toPersistableBundle(@NonNull IkeTunnelConnectionParams params) {
final PersistableBundle result = new PersistableBundle();
- if (params instanceof IkeTunnelConnectionParams) {
- result.putPersistableBundle(
- PARAMS_TYPE_IKE,
- IkeTunnelConnectionParamsUtils.serializeIkeParams(
- (IkeTunnelConnectionParams) params));
- return result;
- } else {
- throw new UnsupportedOperationException("Invalid TunnelConnectionParams type");
- }
+ result.putPersistableBundle(
+ PARAMS_TYPE_IKE,
+ IkeTunnelConnectionParamsUtils.serializeIkeParams(
+ (IkeTunnelConnectionParams) params));
+ return result;
}
- /** Constructs an TunnelConnectionParams by deserializing a PersistableBundle. */
+ /** Constructs an IkeTunnelConnectionParams by deserializing a PersistableBundle. */
@NonNull
- public static TunnelConnectionParams fromPersistableBundle(@NonNull PersistableBundle in) {
+ public static IkeTunnelConnectionParams fromPersistableBundle(@NonNull PersistableBundle in) {
Objects.requireNonNull(in, "PersistableBundle was null");
if (in.keySet().size() != EXPECTED_BUNDLE_KEY_CNT) {
throw new IllegalArgumentException(
- "Expect PersistableBundle to have one element but found: " + in.keySet());
+ String.format(
+ "Expect PersistableBundle to have %d element but found: %d",
+ EXPECTED_BUNDLE_KEY_CNT, in.keySet()));
}
if (in.get(PARAMS_TYPE_IKE) != null) {
@@ -66,7 +63,7 @@
}
throw new IllegalArgumentException(
- "Invalid TunnelConnectionParams type " + in.keySet().iterator().next());
+ "Invalid Tunnel Connection Params type " + in.keySet().iterator().next());
}
private static final class IkeTunnelConnectionParamsUtils {
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index ba63ba4..32ca92c 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -85,54 +85,6 @@
public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
/**
- * Time usage component, describing the particular part of the system
- * that was used for the corresponding amount of time.
- *
- * @hide
- */
- @IntDef(prefix = {"TIME_COMPONENT_"}, value = {
- TIME_COMPONENT_SCREEN,
- TIME_COMPONENT_CPU,
- TIME_COMPONENT_CPU_FOREGROUND,
- TIME_COMPONENT_BLUETOOTH,
- TIME_COMPONENT_CAMERA,
- TIME_COMPONENT_FLASHLIGHT,
- TIME_COMPONENT_MOBILE_RADIO,
- TIME_COMPONENT_SENSORS,
- TIME_COMPONENT_GNSS,
- TIME_COMPONENT_WIFI,
- TIME_COMPONENT_WAKELOCK,
- TIME_COMPONENT_MEMORY,
- TIME_COMPONENT_PHONE,
- TIME_COMPONENT_IDLE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public static @interface TimeComponent {
- }
-
- public static final int TIME_COMPONENT_SCREEN = 0;
- public static final int TIME_COMPONENT_CPU = 1;
- public static final int TIME_COMPONENT_CPU_FOREGROUND = 2;
- public static final int TIME_COMPONENT_BLUETOOTH = 3;
- public static final int TIME_COMPONENT_CAMERA = 4;
- public static final int TIME_COMPONENT_AUDIO = 5;
- public static final int TIME_COMPONENT_VIDEO = 6;
- public static final int TIME_COMPONENT_FLASHLIGHT = 7;
- public static final int TIME_COMPONENT_MOBILE_RADIO = 8;
- public static final int TIME_COMPONENT_SENSORS = 9;
- public static final int TIME_COMPONENT_GNSS = 10;
- public static final int TIME_COMPONENT_WIFI = 11;
- public static final int TIME_COMPONENT_WAKELOCK = 12;
- public static final int TIME_COMPONENT_MEMORY = 13;
- public static final int TIME_COMPONENT_PHONE = 14;
- public static final int TIME_COMPONENT_IDLE = 15;
-
- public static final int TIME_COMPONENT_COUNT = 16;
-
- public static final int FIRST_CUSTOM_TIME_COMPONENT_ID = 1000;
- public static final int LAST_CUSTOM_TIME_COMPONENT_ID = 9999;
-
- /**
* Identifiers of models used for power estimation.
*
* @hide
@@ -166,7 +118,7 @@
* Total power consumed by this consumer, in mAh.
*/
public double getConsumedPower() {
- return mPowerComponents.getTotalConsumedPower();
+ return mPowerComponents.getConsumedPower();
}
/**
@@ -221,11 +173,11 @@
* Returns the amount of time since BatteryStats reset used by the specified component, e.g.
* CPU, WiFi etc.
*
- * @param componentId The ID of the time component, e.g.
- * {@link UidBatteryConsumer#TIME_COMPONENT_CPU}.
+ * @param componentId The ID of the power component, e.g.
+ * {@link UidBatteryConsumer#POWER_COMPONENT_CPU}.
* @return Amount of time in milliseconds.
*/
- public long getUsageDurationMillis(@TimeComponent int componentId) {
+ public long getUsageDurationMillis(@PowerComponent int componentId) {
return mPowerComponents.getUsageDurationMillis(componentId);
}
@@ -248,9 +200,9 @@
final PowerComponents.Builder mPowerComponentsBuilder;
public BaseBuilder(@NonNull String[] customPowerComponentNames,
- int customTimeComponentCount, boolean includePowerModels) {
+ boolean includePowerModels) {
mPowerComponentsBuilder = new PowerComponents.Builder(customPowerComponentNames,
- customTimeComponentCount, includePowerModels);
+ includePowerModels);
}
/**
@@ -296,13 +248,13 @@
/**
* Sets the amount of time used by the specified component, e.g. CPU, WiFi etc.
*
- * @param componentId The ID of the time component, e.g.
- * {@link UidBatteryConsumer#TIME_COMPONENT_CPU}.
+ * @param componentId The ID of the power component, e.g.
+ * {@link UidBatteryConsumer#POWER_COMPONENT_CPU}.
* @param componentUsageTimeMillis Amount of time in microseconds.
*/
@SuppressWarnings("unchecked")
@NonNull
- public T setUsageDurationMillis(@UidBatteryConsumer.TimeComponent int componentId,
+ public T setUsageDurationMillis(@UidBatteryConsumer.PowerComponent int componentId,
long componentUsageTimeMillis) {
mPowerComponentsBuilder.setUsageDurationMillis(componentId, componentUsageTimeMillis);
return (T) this;
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index 8ea59ce..efdef62 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -292,7 +292,6 @@
public static final class Builder {
@NonNull
private final String[] mCustomPowerComponentNames;
- private final int mCustomTimeComponentCount;
private final boolean mIncludePowerModels;
private long mStatsStartTimestampMs;
private int mDischargePercentage;
@@ -309,14 +308,12 @@
private Parcel mHistoryBuffer;
private List<BatteryStats.HistoryTag> mHistoryTagPool;
- public Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount) {
- this(customPowerComponentNames, customTimeComponentCount, false);
+ public Builder(@NonNull String[] customPowerComponentNames) {
+ this(customPowerComponentNames, false);
}
- public Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
- boolean includePowerModels) {
+ public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels) {
mCustomPowerComponentNames = customPowerComponentNames;
- mCustomTimeComponentCount = customTimeComponentCount;
mIncludePowerModels = includePowerModels;
}
@@ -399,7 +396,7 @@
UidBatteryConsumer.Builder builder = mUidBatteryConsumerBuilders.get(uid);
if (builder == null) {
builder = new UidBatteryConsumer.Builder(mCustomPowerComponentNames,
- mCustomTimeComponentCount, mIncludePowerModels, batteryStatsUid);
+ mIncludePowerModels, batteryStatsUid);
mUidBatteryConsumerBuilders.put(uid, builder);
}
return builder;
@@ -415,7 +412,7 @@
SystemBatteryConsumer.Builder builder = mSystemBatteryConsumerBuilders.get(drainType);
if (builder == null) {
builder = new SystemBatteryConsumer.Builder(mCustomPowerComponentNames,
- mCustomTimeComponentCount, mIncludePowerModels, drainType);
+ mIncludePowerModels, drainType);
mSystemBatteryConsumerBuilders.put(drainType, builder);
}
return builder;
@@ -430,7 +427,7 @@
UserBatteryConsumer.Builder builder = mUserBatteryConsumerBuilders.get(userId);
if (builder == null) {
builder = new UserBatteryConsumer.Builder(mCustomPowerComponentNames,
- mCustomTimeComponentCount, mIncludePowerModels, userId);
+ mIncludePowerModels, userId);
mUserBatteryConsumerBuilders.put(userId, builder);
}
return builder;
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index a0a41f4..47a2edc 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -26,12 +26,10 @@
class PowerComponents {
private static final int CUSTOM_POWER_COMPONENT_OFFSET = BatteryConsumer.POWER_COMPONENT_COUNT
- BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
- private static final int CUSTOM_TIME_COMPONENT_OFFSET = BatteryConsumer.TIME_COMPONENT_COUNT
- - BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID;
- private final double mTotalConsumedPowerMah;
+ private final double mConsumedPowerMah;
private final double[] mPowerComponentsMah;
- private final long[] mTimeComponentsMs;
+ private final long[] mUsageDurationsMs;
private final int mCustomPowerComponentCount;
private final byte[] mPowerModels;
// Not written to Parcel and must be explicitly restored during the parent object's unparceling
@@ -41,16 +39,16 @@
mCustomPowerComponentNames = builder.mCustomPowerComponentNames;
mCustomPowerComponentCount = mCustomPowerComponentNames.length;
mPowerComponentsMah = builder.mPowerComponentsMah;
- mTimeComponentsMs = builder.mTimeComponentsMs;
- mTotalConsumedPowerMah = builder.getTotalPower();
+ mUsageDurationsMs = builder.mUsageDurationsMs;
+ mConsumedPowerMah = builder.getTotalPower();
mPowerModels = builder.mPowerModels;
}
PowerComponents(@NonNull Parcel source) {
- mTotalConsumedPowerMah = source.readDouble();
+ mConsumedPowerMah = source.readDouble();
mCustomPowerComponentCount = source.readInt();
mPowerComponentsMah = source.createDoubleArray();
- mTimeComponentsMs = source.createLongArray();
+ mUsageDurationsMs = source.createLongArray();
if (source.readBoolean()) {
mPowerModels = new byte[BatteryConsumer.POWER_COMPONENT_COUNT];
source.readByteArray(mPowerModels);
@@ -61,10 +59,10 @@
/** Writes contents to Parcel */
void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeDouble(mTotalConsumedPowerMah);
+ dest.writeDouble(mConsumedPowerMah);
dest.writeInt(mCustomPowerComponentCount);
dest.writeDoubleArray(mPowerComponentsMah);
- dest.writeLongArray(mTimeComponentsMs);
+ dest.writeLongArray(mUsageDurationsMs);
if (mPowerModels != null) {
dest.writeBoolean(true);
dest.writeByteArray(mPowerModels);
@@ -76,8 +74,8 @@
/**
* Total power consumed by this consumer, in mAh.
*/
- public double getTotalConsumedPower() {
- return mTotalConsumedPowerMah;
+ public double getConsumedPower() {
+ return mConsumedPowerMah;
}
/**
@@ -152,17 +150,17 @@
/**
* Returns the amount of time used by the specified component, e.g. CPU, WiFi etc.
*
- * @param componentId The ID of the time component, e.g.
- * {@link BatteryConsumer#TIME_COMPONENT_CPU}.
+ * @param componentId The ID of the power component, e.g.
+ * {@link BatteryConsumer#POWER_COMPONENT_CPU}.
* @return Amount of time in milliseconds.
*/
- public long getUsageDurationMillis(@BatteryConsumer.TimeComponent int componentId) {
- if (componentId >= BatteryConsumer.TIME_COMPONENT_COUNT) {
+ public long getUsageDurationMillis(@BatteryConsumer.PowerComponent int componentId) {
+ if (componentId >= BatteryConsumer.POWER_COMPONENT_COUNT) {
throw new IllegalArgumentException(
- "Unsupported time component ID: " + componentId);
+ "Unsupported power component ID: " + componentId);
}
try {
- return mTimeComponentsMs[componentId];
+ return mUsageDurationsMs[componentId];
} catch (ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException("Unsupported power component ID: " + componentId);
}
@@ -175,15 +173,15 @@
* @return Amount of time in milliseconds.
*/
public long getUsageDurationForCustomComponentMillis(int componentId) {
- if (componentId < BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID) {
+ if (componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID) {
throw new IllegalArgumentException(
- "Unsupported custom time component ID: " + componentId);
+ "Unsupported custom power component ID: " + componentId);
}
try {
- return mTimeComponentsMs[CUSTOM_TIME_COMPONENT_OFFSET + componentId];
+ return mUsageDurationsMs[CUSTOM_POWER_COMPONENT_OFFSET + componentId];
} catch (ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException(
- "Unsupported custom time component ID: " + componentId);
+ "Unsupported custom power component ID: " + componentId);
}
}
@@ -192,13 +190,13 @@
}
/**
- * Returns the largest usage duration among all time components.
+ * Returns the largest usage duration among all power components.
*/
public long getMaxComponentUsageDurationMillis() {
long max = 0;
- for (int i = mTimeComponentsMs.length - 1; i >= 0; i--) {
- if (mTimeComponentsMs[i] > max) {
- max = mTimeComponentsMs[i];
+ for (int i = mUsageDurationsMs.length - 1; i >= 0; i--) {
+ if (mUsageDurationsMs[i] > max) {
+ max = mUsageDurationsMs[i];
}
}
return max;
@@ -210,17 +208,15 @@
static final class Builder {
private final double[] mPowerComponentsMah;
private final String[] mCustomPowerComponentNames;
- private final long[] mTimeComponentsMs;
+ private final long[] mUsageDurationsMs;
private final byte[] mPowerModels;
- Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
- boolean includePowerModels) {
+ Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels) {
mCustomPowerComponentNames = customPowerComponentNames;
int powerComponentCount =
BatteryConsumer.POWER_COMPONENT_COUNT + mCustomPowerComponentNames.length;
mPowerComponentsMah = new double[powerComponentCount];
- mTimeComponentsMs =
- new long[BatteryConsumer.TIME_COMPONENT_COUNT + customTimeComponentCount];
+ mUsageDurationsMs = new long[powerComponentCount];
if (includePowerModels) {
mPowerModels = new byte[BatteryConsumer.POWER_COMPONENT_COUNT];
} else {
@@ -281,22 +277,22 @@
/**
* Sets the amount of time used by the specified component, e.g. CPU, WiFi etc.
*
- * @param componentId The ID of the time component, e.g.
- * {@link BatteryConsumer#TIME_COMPONENT_CPU}.
+ * @param componentId The ID of the power component, e.g.
+ * {@link BatteryConsumer#POWER_COMPONENT_CPU}.
* @param componentUsageDurationMillis Amount of time in milliseconds.
*/
@NonNull
- public Builder setUsageDurationMillis(@BatteryConsumer.TimeComponent int componentId,
+ public Builder setUsageDurationMillis(@BatteryConsumer.PowerComponent int componentId,
long componentUsageDurationMillis) {
- if (componentId >= BatteryConsumer.TIME_COMPONENT_COUNT) {
+ if (componentId >= BatteryConsumer.POWER_COMPONENT_COUNT) {
throw new IllegalArgumentException(
- "Unsupported time component ID: " + componentId);
+ "Unsupported power component ID: " + componentId);
}
try {
- mTimeComponentsMs[componentId] = componentUsageDurationMillis;
+ mUsageDurationsMs[componentId] = componentUsageDurationMillis;
} catch (ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException(
- "Unsupported time component ID: " + componentId);
+ "Unsupported power component ID: " + componentId);
}
return this;
}
@@ -310,16 +306,16 @@
@NonNull
public Builder setUsageDurationForCustomComponentMillis(int componentId,
long componentUsageDurationMillis) {
- if (componentId < BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID) {
+ if (componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID) {
throw new IllegalArgumentException(
- "Unsupported custom time component ID: " + componentId);
+ "Unsupported custom power component ID: " + componentId);
}
try {
- mTimeComponentsMs[CUSTOM_TIME_COMPONENT_OFFSET + componentId] =
+ mUsageDurationsMs[CUSTOM_POWER_COMPONENT_OFFSET + componentId] =
componentUsageDurationMillis;
} catch (ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException(
- "Unsupported custom time component ID: " + componentId);
+ "Unsupported custom power component ID: " + componentId);
}
return this;
}
@@ -328,8 +324,8 @@
for (int i = mPowerComponentsMah.length - 1; i >= 0; i--) {
mPowerComponentsMah[i] += other.mPowerComponentsMah[i];
}
- for (int i = mTimeComponentsMs.length - 1; i >= 0; i--) {
- mTimeComponentsMs[i] += other.mTimeComponentsMs[i];
+ for (int i = mUsageDurationsMs.length - 1; i >= 0; i--) {
+ mUsageDurationsMs[i] += other.mUsageDurationsMs[i];
}
}
diff --git a/core/java/android/os/SystemBatteryConsumer.java b/core/java/android/os/SystemBatteryConsumer.java
index 1327978..7618339 100644
--- a/core/java/android/os/SystemBatteryConsumer.java
+++ b/core/java/android/os/SystemBatteryConsumer.java
@@ -147,9 +147,9 @@
private double mPowerConsumedByAppsMah;
private List<UidBatteryConsumer.Builder> mUidBatteryConsumers;
- Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
+ Builder(@NonNull String[] customPowerComponentNames,
boolean includePowerModels, @DrainType int drainType) {
- super(customPowerComponentNames, customTimeComponentCount, includePowerModels);
+ super(customPowerComponentNames, includePowerModels);
mDrainType = drainType;
}
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index 92e9603..b1fb570 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -139,9 +139,9 @@
public long mTimeInBackgroundMs;
private boolean mExcludeFromBatteryUsageStats;
- public Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
+ public Builder(@NonNull String[] customPowerComponentNames,
boolean includePowerModels, @NonNull BatteryStats.Uid batteryStatsUid) {
- super(customPowerComponentNames, customTimeComponentCount, includePowerModels);
+ super(customPowerComponentNames, includePowerModels);
mBatteryStatsUid = batteryStatsUid;
mUid = batteryStatsUid.getUid();
}
diff --git a/core/java/android/os/UserBatteryConsumer.java b/core/java/android/os/UserBatteryConsumer.java
index de0a707..d0d0d38 100644
--- a/core/java/android/os/UserBatteryConsumer.java
+++ b/core/java/android/os/UserBatteryConsumer.java
@@ -77,9 +77,9 @@
private final int mUserId;
private List<UidBatteryConsumer.Builder> mUidBatteryConsumers;
- Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
- boolean includePowerModels, int userId) {
- super(customPowerComponentNames, customTimeComponentCount, includePowerModels);
+ Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels,
+ int userId) {
+ super(customPowerComponentNames, includePowerModels);
mUserId = userId;
}
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index b3502f3..95962c8 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -554,9 +554,12 @@
/**
* Query the estimated durations of the given primitives.
*
- * The returned array will be the same length as the query array and the value at a given index
- * will contain the duration in milliseconds of the effect at the same index in the querying
- * array.
+ * <p>The returned array will be the same length as the query array and the value at a given
+ * index will contain the duration in milliseconds of the effect at the same index in the
+ * querying array.
+ *
+ * <p>The duration will be positive for primitives that are supported and zero for the
+ * unsupported ones, in correspondence with {@link #arePrimitivesSupported(int...)}.
*
* @param primitiveIds Which primitives to query for.
* @return The duration of each primitive, with zeroes for primitives that are not supported.
diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java
index d73469c..597df08 100644
--- a/core/java/android/os/VibratorInfo.java
+++ b/core/java/android/os/VibratorInfo.java
@@ -260,7 +260,7 @@
*/
public int getPrimitiveDuration(
@VibrationEffect.Composition.PrimitiveType int primitiveId) {
- return mSupportedPrimitives.get(primitiveId);
+ return mSupportedPrimitives != null ? mSupportedPrimitives.get(primitiveId) : 0;
}
/**
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index fe3197a..c68f878 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -167,6 +167,27 @@
*/
const @utf8InCpp String METRICS_MILLIS_SINCE_OLDEST_PENDING_READ = "millisSinceOldestPendingRead";
/**
+ * Metrics key for whether read logs are enabled. The value is a boolean.
+ */
+ const @utf8InCpp String METRICS_READ_LOGS_ENABLED = "readLogsEnabled";
+ /**
+ * Metrics key for the storage health status. The value is an int.
+ */
+ const @utf8InCpp String METRICS_STORAGE_HEALTH_STATUS_CODE = "storageHealthStatusCode";
+ /**
+ * Metrics key for the data loader status. The value is an int.
+ */
+ const @utf8InCpp String METRICS_DATA_LOADER_STATUS_CODE = "dataLoaderStatusCode";
+ /**
+ * Metrics key for duration since last data loader binding attempt. The value is a long.
+ */
+ const @utf8InCpp String METRICS_MILLIS_SINCE_LAST_DATA_LOADER_BIND = "millisSinceLastDataLoaderBind";
+ /**
+ * Metrics key for delay in milliseconds to retry data loader binding. The value is a long.
+ */
+ const @utf8InCpp String METRICS_DATA_LOADER_BIND_DELAY_MILLIS = "dataLoaderBindDelayMillis";
+
+ /**
* Return a bundle containing the requested metrics keys and their values.
*/
PersistableBundle getMetrics(int storageId);
diff --git a/core/java/android/os/incremental/IncrementalMetrics.java b/core/java/android/os/incremental/IncrementalMetrics.java
index 44dea1be..98eb431 100644
--- a/core/java/android/os/incremental/IncrementalMetrics.java
+++ b/core/java/android/os/incremental/IncrementalMetrics.java
@@ -36,4 +36,39 @@
public long getMillisSinceOldestPendingRead() {
return mData.getLong(IIncrementalService.METRICS_MILLIS_SINCE_OLDEST_PENDING_READ, -1);
}
+
+ /**
+ * @return Whether read logs are enabled
+ */
+ public boolean getReadLogsEnabled() {
+ return mData.getBoolean(IIncrementalService.METRICS_READ_LOGS_ENABLED, false);
+ }
+
+ /**
+ * @return storage health status code. @see android.os.incremental.IStorageHealthListener
+ */
+ public int getStorageHealthStatusCode() {
+ return mData.getInt(IIncrementalService.METRICS_STORAGE_HEALTH_STATUS_CODE, -1);
+ }
+
+ /**
+ * @return data loader status code. @see android.content.pm.IDataLoaderStatusListener
+ */
+ public int getDataLoaderStatusCode() {
+ return mData.getInt(IIncrementalService.METRICS_DATA_LOADER_STATUS_CODE, -1);
+ }
+
+ /**
+ * @return duration since last data loader binding attempt
+ */
+ public long getMillisSinceLastDataLoaderBind() {
+ return mData.getLong(IIncrementalService.METRICS_MILLIS_SINCE_LAST_DATA_LOADER_BIND, -1);
+ }
+
+ /**
+ * @return delay in milliseconds to retry data loader binding
+ */
+ public long getDataLoaderBindDelayMillis() {
+ return mData.getLong(IIncrementalService.METRICS_DATA_LOADER_BIND_DELAY_MILLIS, -1);
+ }
}
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index a56e8218..ca132e9 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -725,12 +725,14 @@
* Get the platform permissions which belong to a particular permission group.
*
* @param permissionGroupName The permission group whose permissions are desired
+ * @param executor Executor on which to invoke the callback
* @param callback A callback which will receive a list of the platform permissions in the
* group, or empty if the group is not a valid platform group, or there
* was an exception.
*/
@RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING)
public void getPlatformPermissionsForGroup(@NonNull String permissionGroupName,
+ @NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<List<String>> callback) {
enforceSomePermissionsGrantedToSelf(
Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING);
@@ -738,14 +740,19 @@
AndroidFuture<List<String>> future = new AndroidFuture<>();
service.getPlatformPermissionsForGroup(permissionGroupName, future);
return future;
- }).whenComplete((result, err) -> {
- if (err != null) {
- Log.e(TAG, "Failed to get permissions of " + permissionGroupName, err);
- callback.accept(new ArrayList<>());
- } else {
- callback.accept(result);
+ }).whenCompleteAsync((result, err) -> {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (err != null) {
+ Log.e(TAG, "Failed to get permissions of " + permissionGroupName, err);
+ callback.accept(new ArrayList<>());
+ } else {
+ callback.accept(result);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
- });
+ }, executor);
}
/**
@@ -753,26 +760,32 @@
* permission.
*
* @param permissionName The permission name whose group is desired
+ * @param executor Executor on which to invoke the callback
* @param callback A callback which will receive the name of the permission group this
* permission belongs to, or null if it has no group, is not a platform
* permission, or there was an exception.
*/
@RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING)
public void getGroupOfPlatformPermission(@NonNull String permissionName,
- @NonNull Consumer<String> callback) {
+ @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<String> callback) {
enforceSomePermissionsGrantedToSelf(
Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING);
mRemoteService.postAsync(service -> {
AndroidFuture<String> future = new AndroidFuture<>();
service.getGroupOfPlatformPermission(permissionName, future);
return future;
- }).whenComplete((result, err) -> {
- if (err != null) {
- Log.e(TAG, "Failed to get group of " + permissionName, err);
- callback.accept(null);
- } else {
- callback.accept(result);
+ }).whenCompleteAsync((result, err) -> {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (err != null) {
+ Log.e(TAG, "Failed to get group of " + permissionName, err);
+ callback.accept(null);
+ } else {
+ callback.accept(result);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
- });
+ }, executor);
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f8991ce..98abd96 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -83,6 +83,7 @@
import android.util.Log;
import android.util.MemoryIntArray;
import android.view.Display;
+import android.view.Window;
import android.view.WindowManager.LayoutParams;
import com.android.internal.annotations.GuardedBy;
@@ -6606,7 +6607,6 @@
*
* @hide
*/
- @Readable
public static final String ALWAYS_ON_VPN_APP = "always_on_vpn_app";
/**
@@ -13372,6 +13372,19 @@
public static final String WINDOW_ANIMATION_SCALE = "window_animation_scale";
/**
+ * Setting to disable cross-window blurs. This includes window blur behind, (see
+ * {@link LayoutParams#setBlurBehindRadius}) and window background blur (see
+ * {@link Window#setBackgroundBlurRadius}).
+ *
+ * The value is a boolean (1 or 0).
+ * @hide
+ */
+ @TestApi
+ @Readable
+ @SuppressLint("NoSettingsProvider")
+ public static final String DISABLE_WINDOW_BLURS = "disable_window_blurs";
+
+ /**
* Scaling factor for activity transition animations.
*
* The value is a float. Setting to 0.0f will disable window animations.
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 5a89cdf..0b11aeb 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -66,9 +66,6 @@
public static final int KM_TAG_CALLER_NONCE = Tag.CALLER_NONCE; // KM_BOOL | 7;
public static final int KM_TAG_MIN_MAC_LENGTH = Tag.MIN_MAC_LENGTH; // KM_UINT | 8;
- public static final int KM_TAG_BLOB_USAGE_REQUIREMENTS =
- Tag.BLOB_USAGE_REQUIREMENTS; // KM_ENUM | 705;
-
public static final int KM_TAG_RSA_PUBLIC_EXPONENT = Tag.RSA_PUBLIC_EXPONENT; // KM_ULONG | 200;
public static final int KM_TAG_INCLUDE_UNIQUE_ID = Tag.INCLUDE_UNIQUE_ID; // KM_BOOL | 202;
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 3c53e8f..bacc6ec 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -349,7 +349,7 @@
private final HotwordDetectedResult mHotwordDetectedResult;
private final ParcelFileDescriptor mAudioStream;
- private EventPayload(boolean triggerAvailable, boolean captureAvailable,
+ EventPayload(boolean triggerAvailable, boolean captureAvailable,
AudioFormat audioFormat, int captureSession, byte[] data) {
this(triggerAvailable, captureAvailable, audioFormat, captureSession, data, null,
null);
diff --git a/core/java/android/service/voice/HotwordDetectedResult.java b/core/java/android/service/voice/HotwordDetectedResult.java
index f5d796f..e50de1c 100644
--- a/core/java/android/service/voice/HotwordDetectedResult.java
+++ b/core/java/android/service/voice/HotwordDetectedResult.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.media.MediaSyncEvent;
import android.os.Parcelable;
import android.os.PersistableBundle;
@@ -53,9 +54,17 @@
}
/**
+ * A {@code MediaSyncEvent} that allows the {@link HotwordDetector} to recapture the audio
+ * that contains the hotword trigger. This must be obtained using
+ * {@link android.media.AudioRecord#shareAudioHistory(String, long)}.
+ * <p>
+ * This can be {@code null} if reprocessing the hotword trigger isn't required.
+ */
+ @Nullable
+ private MediaSyncEvent mMediaSyncEvent = null;
+
+ /**
* Byte offset in the audio stream when the trigger event happened.
- *
- * <p>If unset, the most recent bytes in the audio stream will be used.
*/
private final int mByteOffset;
private static int defaultByteOffset() {
@@ -84,7 +93,7 @@
/**
* Returns the maximum values of {@link #getScore} and {@link #getPersonalizedScore}.
- *
+ * <p>
* The float value should be calculated as {@code getScore() / getMaxScore()}.
*/
public static int getMaxScore() {
@@ -159,6 +168,7 @@
@DataClass.Generated.Member
/* package-private */ HotwordDetectedResult(
@HotwordDetector.HotwordConfidenceLevelValue int confidenceLevel,
+ @Nullable MediaSyncEvent mediaSyncEvent,
int byteOffset,
int score,
int personalizedScore,
@@ -167,6 +177,7 @@
this.mConfidenceLevel = confidenceLevel;
com.android.internal.util.AnnotationValidations.validate(
HotwordDetector.HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
+ this.mMediaSyncEvent = mediaSyncEvent;
this.mByteOffset = byteOffset;
this.mScore = score;
this.mPersonalizedScore = personalizedScore;
@@ -187,9 +198,19 @@
}
/**
+ * A {@code MediaSyncEvent} that allows the {@link HotwordDetector} to recapture the audio
+ * that contains the hotword trigger. This must be obtained using
+ * {@link android.media.AudioRecord#shareAudioHistory(String, long)}.
+ * <p>
+ * This can be {@code null} if reprocessing the hotword trigger isn't required.
+ */
+ @DataClass.Generated.Member
+ public @Nullable MediaSyncEvent getMediaSyncEvent() {
+ return mMediaSyncEvent;
+ }
+
+ /**
* Byte offset in the audio stream when the trigger event happened.
- *
- * <p>If unset, the most recent bytes in the audio stream will be used.
*/
@DataClass.Generated.Member
public int getByteOffset() {
@@ -237,6 +258,9 @@
*
* <p>The use of this method is discouraged, and support for it will be removed in future
* versions of Android.
+ *
+ * <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents
+ * that can be used to communicate with other processes.
*/
@DataClass.Generated.Member
public @NonNull PersistableBundle getExtras() {
@@ -251,6 +275,7 @@
return "HotwordDetectedResult { " +
"confidenceLevel = " + mConfidenceLevel + ", " +
+ "mediaSyncEvent = " + mMediaSyncEvent + ", " +
"byteOffset = " + mByteOffset + ", " +
"score = " + mScore + ", " +
"personalizedScore = " + mPersonalizedScore + ", " +
@@ -273,6 +298,7 @@
//noinspection PointlessBooleanExpression
return true
&& mConfidenceLevel == that.mConfidenceLevel
+ && java.util.Objects.equals(mMediaSyncEvent, that.mMediaSyncEvent)
&& mByteOffset == that.mByteOffset
&& mScore == that.mScore
&& mPersonalizedScore == that.mPersonalizedScore
@@ -288,6 +314,7 @@
int _hash = 1;
_hash = 31 * _hash + mConfidenceLevel;
+ _hash = 31 * _hash + java.util.Objects.hashCode(mMediaSyncEvent);
_hash = 31 * _hash + mByteOffset;
_hash = 31 * _hash + mScore;
_hash = 31 * _hash + mPersonalizedScore;
@@ -302,7 +329,11 @@
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
+ byte flg = 0;
+ if (mMediaSyncEvent != null) flg |= 0x2;
+ dest.writeByte(flg);
dest.writeInt(mConfidenceLevel);
+ if (mMediaSyncEvent != null) dest.writeTypedObject(mMediaSyncEvent, flags);
dest.writeInt(mByteOffset);
dest.writeInt(mScore);
dest.writeInt(mPersonalizedScore);
@@ -321,7 +352,9 @@
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
+ byte flg = in.readByte();
int confidenceLevel = in.readInt();
+ MediaSyncEvent mediaSyncEvent = (flg & 0x2) == 0 ? null : (MediaSyncEvent) in.readTypedObject(MediaSyncEvent.CREATOR);
int byteOffset = in.readInt();
int score = in.readInt();
int personalizedScore = in.readInt();
@@ -331,6 +364,7 @@
this.mConfidenceLevel = confidenceLevel;
com.android.internal.util.AnnotationValidations.validate(
HotwordDetector.HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
+ this.mMediaSyncEvent = mediaSyncEvent;
this.mByteOffset = byteOffset;
this.mScore = score;
this.mPersonalizedScore = personalizedScore;
@@ -364,6 +398,7 @@
public static final class Builder {
private @HotwordDetector.HotwordConfidenceLevelValue int mConfidenceLevel;
+ private @Nullable MediaSyncEvent mMediaSyncEvent;
private int mByteOffset;
private int mScore;
private int mPersonalizedScore;
@@ -387,14 +422,27 @@
}
/**
+ * A {@code MediaSyncEvent} that allows the {@link HotwordDetector} to recapture the audio
+ * that contains the hotword trigger. This must be obtained using
+ * {@link android.media.AudioRecord#shareAudioHistory(String, long)}.
+ * <p>
+ * This can be {@code null} if reprocessing the hotword trigger isn't required.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setMediaSyncEvent(@NonNull MediaSyncEvent value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x2;
+ mMediaSyncEvent = value;
+ return this;
+ }
+
+ /**
* Byte offset in the audio stream when the trigger event happened.
- *
- * <p>If unset, the most recent bytes in the audio stream will be used.
*/
@DataClass.Generated.Member
public @NonNull Builder setByteOffset(int value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x2;
+ mBuilderFieldsSet |= 0x4;
mByteOffset = value;
return this;
}
@@ -407,7 +455,7 @@
@DataClass.Generated.Member
public @NonNull Builder setScore(int value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x4;
+ mBuilderFieldsSet |= 0x8;
mScore = value;
return this;
}
@@ -420,7 +468,7 @@
@DataClass.Generated.Member
public @NonNull Builder setPersonalizedScore(int value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x8;
+ mBuilderFieldsSet |= 0x10;
mPersonalizedScore = value;
return this;
}
@@ -433,7 +481,7 @@
@DataClass.Generated.Member
public @NonNull Builder setHotwordPhraseId(int value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x10;
+ mBuilderFieldsSet |= 0x20;
mHotwordPhraseId = value;
return this;
}
@@ -449,11 +497,14 @@
*
* <p>The use of this method is discouraged, and support for it will be removed in future
* versions of Android.
+ *
+ * <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents
+ * that can be used to communicate with other processes.
*/
@DataClass.Generated.Member
public @NonNull Builder setExtras(@NonNull PersistableBundle value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x20;
+ mBuilderFieldsSet |= 0x40;
mExtras = value;
return this;
}
@@ -461,28 +512,32 @@
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull HotwordDetectedResult build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x40; // Mark builder used
+ mBuilderFieldsSet |= 0x80; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mConfidenceLevel = defaultConfidenceLevel();
}
if ((mBuilderFieldsSet & 0x2) == 0) {
- mByteOffset = defaultByteOffset();
+ mMediaSyncEvent = null;
}
if ((mBuilderFieldsSet & 0x4) == 0) {
- mScore = defaultScore();
+ mByteOffset = defaultByteOffset();
}
if ((mBuilderFieldsSet & 0x8) == 0) {
- mPersonalizedScore = defaultPersonalizedScore();
+ mScore = defaultScore();
}
if ((mBuilderFieldsSet & 0x10) == 0) {
- mHotwordPhraseId = defaultHotwordPhraseId();
+ mPersonalizedScore = defaultPersonalizedScore();
}
if ((mBuilderFieldsSet & 0x20) == 0) {
+ mHotwordPhraseId = defaultHotwordPhraseId();
+ }
+ if ((mBuilderFieldsSet & 0x40) == 0) {
mExtras = defaultExtras();
}
HotwordDetectedResult o = new HotwordDetectedResult(
mConfidenceLevel,
+ mMediaSyncEvent,
mByteOffset,
mScore,
mPersonalizedScore,
@@ -492,7 +547,7 @@
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x40) != 0) {
+ if ((mBuilderFieldsSet & 0x80) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -500,10 +555,10 @@
}
@DataClass.Generated(
- time = 1616965644404L,
+ time = 1619059352684L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java",
- inputSignatures = "public static final int BYTE_OFFSET_UNSET\nprivate final @android.service.voice.HotwordDetector.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate final int mByteOffset\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int defaultConfidenceLevel()\nprivate static int defaultByteOffset()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+ inputSignatures = "public static final int BYTE_OFFSET_UNSET\nprivate final @android.service.voice.HotwordDetector.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate final int mByteOffset\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int defaultConfidenceLevel()\nprivate static int defaultByteOffset()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index ea854e8..7e0117d 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -30,6 +30,7 @@
import android.content.ContentCaptureOptions;
import android.content.Context;
import android.content.Intent;
+import android.hardware.soundtrigger.SoundTrigger;
import android.media.AudioFormat;
import android.os.Bundle;
import android.os.Handler;
@@ -133,7 +134,7 @@
private final IHotwordDetectionService mInterface = new IHotwordDetectionService.Stub() {
@Override
public void detectFromDspSource(
- ParcelFileDescriptor audioStream,
+ SoundTrigger.KeyphraseRecognitionEvent event,
AudioFormat audioFormat,
long timeoutMillis,
IDspHotwordDetectionCallback callback)
@@ -143,8 +144,9 @@
}
mHandler.sendMessage(obtainMessage(HotwordDetectionService::onDetect,
HotwordDetectionService.this,
- audioStream,
- audioFormat,
+ new AlwaysOnHotwordDetector.EventPayload(
+ event.triggerInData, event.captureAvailable,
+ event.captureFormat, event.captureSession, event.data),
timeoutMillis,
new Callback(callback)));
}
@@ -178,8 +180,6 @@
mHandler.sendMessage(obtainMessage(
HotwordDetectionService::onDetect,
HotwordDetectionService.this,
- audioStream,
- audioFormat,
new Callback(callback)));
break;
case AUDIO_SOURCE_EXTERNAL:
@@ -246,13 +246,42 @@
* the application fails to abide by the timeout, system will close the
* microphone and cancel the operation.
* @param callback The callback to use for responding to the detection request.
+ * @deprecated Implement
+ * {@link #onDetect(AlwaysOnHotwordDetector.EventPayload, long, Callback)} instead.
+ *
+ * @hide
+ */
+ @Deprecated
+ @SystemApi
+ public void onDetect(
+ @NonNull ParcelFileDescriptor audioStream,
+ @NonNull AudioFormat audioFormat,
+ @DurationMillisLong long timeoutMillis,
+ @NonNull Callback callback) {
+ // TODO: Add a helpful error message.
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Called when the device hardware (such as a DSP) detected the hotword, to request second stage
+ * validation before handing over the audio to the {@link AlwaysOnHotwordDetector}.
+ * <p>
+ * After {@code callback} is invoked or {@code timeoutMillis} has passed, and invokes the
+ * appropriate {@link AlwaysOnHotwordDetector.Callback callback}.
+ *
+ * @param eventPayload Payload data for the hardware detection event. This may contain the
+ * trigger audio, if requested when calling
+ * {@link AlwaysOnHotwordDetector#startRecognition(int)}.
+ * @param timeoutMillis Timeout in milliseconds for the operation to invoke the callback. If
+ * the application fails to abide by the timeout, system will close the
+ * microphone and cancel the operation.
+ * @param callback The callback to use for responding to the detection request.
*
* @hide
*/
@SystemApi
public void onDetect(
- @NonNull ParcelFileDescriptor audioStream,
- @NonNull AudioFormat audioFormat,
+ @NonNull AlwaysOnHotwordDetector.EventPayload eventPayload,
@DurationMillisLong long timeoutMillis,
@NonNull Callback callback) {
// TODO: Add a helpful error message.
@@ -305,7 +334,9 @@
* @param audioFormat Format of the supplied audio
* @param callback The callback to use for responding to the detection request.
* {@link Callback#onRejected(HotwordRejectedResult) callback.onRejected} cannot be used here.
+ * @deprecated Implement {@link #onDetect(Callback)} instead.
*/
+ @Deprecated
public void onDetect(
@NonNull ParcelFileDescriptor audioStream,
@NonNull AudioFormat audioFormat,
@@ -316,6 +347,22 @@
/**
* Called when the {@link VoiceInteractionService} requests that this service
+ * {@link HotwordDetector#startRecognition() start} hotword recognition on audio coming directly
+ * from the device microphone.
+ * <p>
+ * On successful detection of a hotword, call
+ * {@link Callback#onDetected(HotwordDetectedResult)}.
+ *
+ * @param callback The callback to use for responding to the detection request.
+ * {@link Callback#onRejected(HotwordRejectedResult) callback.onRejected} cannot be used here.
+ */
+ public void onDetect(@NonNull Callback callback) {
+ // TODO: Add a helpful error message.
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Called when the {@link VoiceInteractionService} requests that this service
* {@link HotwordDetector#startRecognition(ParcelFileDescriptor, AudioFormat,
* PersistableBundle)} run} hotword recognition on audio coming from an external connected
* microphone.
diff --git a/core/java/android/service/voice/IHotwordDetectionService.aidl b/core/java/android/service/voice/IHotwordDetectionService.aidl
index 2ffe787..7ba0098 100644
--- a/core/java/android/service/voice/IHotwordDetectionService.aidl
+++ b/core/java/android/service/voice/IHotwordDetectionService.aidl
@@ -16,6 +16,8 @@
package android.service.voice;
+import android.content.ContentCaptureOptions;
+import android.hardware.soundtrigger.SoundTrigger;
import android.media.AudioFormat;
import android.os.IRemoteCallback;
import android.os.ParcelFileDescriptor;
@@ -23,7 +25,6 @@
import android.os.SharedMemory;
import android.service.voice.IDspHotwordDetectionCallback;
import android.view.contentcapture.IContentCaptureManager;
-import android.content.ContentCaptureOptions;
/**
* Provide the interface to communicate with hotword detection service.
@@ -32,7 +33,7 @@
*/
oneway interface IHotwordDetectionService {
void detectFromDspSource(
- in ParcelFileDescriptor audioStream,
+ in SoundTrigger.KeyphraseRecognitionEvent event,
in AudioFormat audioFormat,
long timeoutMillis,
in IDspHotwordDetectionCallback callback);
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 2a25227..b5c838b 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -420,9 +420,13 @@
*
* @see #createAlwaysOnHotwordDetector(String, Locale, PersistableBundle, SharedMemory,
* AlwaysOnHotwordDetector.Callback)
+ * @deprecated Use
+ * {@link #createHotwordDetector(PersistableBundle, SharedMemory, HotwordDetector.Callback)}
+ * instead.
*
* @hide
*/
+ @Deprecated
@SystemApi
@RequiresPermission(Manifest.permission.MANAGE_HOTWORD_DETECTION)
@NonNull
@@ -445,6 +449,58 @@
}
/**
+ * Creates a {@link HotwordDetector} and initializes the application's
+ * {@link HotwordDetectionService} using {@code options} and {code sharedMemory}.
+ *
+ * <p>To be able to call this, you need to set android:hotwordDetectionService in the
+ * android.voice_interaction metadata file to a valid hotword detection service, and set
+ * android:isolatedProcess="true" in the hotword detection service's declaration. Otherwise,
+ * this throws an {@link IllegalStateException}.
+ *
+ * <p>This instance must be retained and used by the client.
+ * Calling this a second time invalidates the previously created hotword detector
+ * which can no longer be used to manage recognition.
+ *
+ * <p>Using this has a noticeable impact on battery, since the microphone is kept open
+ * for the lifetime of the recognition {@link HotwordDetector#startRecognition() session}. On
+ * devices where hardware filtering is available (such as through a DSP), it's highly
+ * recommended to use {@link #createAlwaysOnHotwordDetector} instead.
+ *
+ * @param options Application configuration data to be provided to the
+ * {@link HotwordDetectionService}. PersistableBundle does not allow any remotable objects or
+ * other contents that can be used to communicate with other processes.
+ * @param sharedMemory The unrestricted data blob to be provided to the
+ * {@link HotwordDetectionService}. Use this to provide hotword models or other such data to the
+ * sandboxed process.
+ * @param callback The callback to notify of detection events.
+ * @return A hotword detector for the given audio format.
+ *
+ * @see #createAlwaysOnHotwordDetector(String, Locale, PersistableBundle, SharedMemory,
+ * AlwaysOnHotwordDetector.Callback)
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_HOTWORD_DETECTION)
+ @NonNull
+ public final HotwordDetector createHotwordDetector(
+ @Nullable PersistableBundle options,
+ @Nullable SharedMemory sharedMemory,
+ @NonNull HotwordDetector.Callback callback) {
+ if (mSystemService == null) {
+ throw new IllegalStateException("Not available until onReady() is called");
+ }
+ synchronized (mLock) {
+ // Allow only one concurrent recognition via the APIs.
+ safelyShutdownHotwordDetector();
+ mSoftwareHotwordDetector =
+ new SoftwareHotwordDetector(
+ mSystemService, null, options, sharedMemory, callback);
+ }
+ return mSoftwareHotwordDetector;
+ }
+
+ /**
* Creates an {@link KeyphraseModelManager} to use for enrolling voice models outside of the
* pre-bundled system voice models.
* @hide
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 87fb611..53bde36 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -254,6 +254,7 @@
private int mDisplayState;
SurfaceControl mSurfaceControl = new SurfaceControl();
+ SurfaceControl mBbqSurfaceControl;
BLASTBufferQueue mBlastBufferQueue;
final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
@@ -976,6 +977,15 @@
View.VISIBLE, 0, -1, mWinFrames, mMergedConfiguration, mSurfaceControl,
mInsetsState, mTempControls, mSurfaceSize);
if (mSurfaceControl.isValid()) {
+ if (mBbqSurfaceControl == null) {
+ mBbqSurfaceControl = new SurfaceControl.Builder()
+ .setName("Wallpaper BBQ wrapper")
+ .setHidden(false)
+ .setBLASTLayer()
+ .setParent(mSurfaceControl)
+ .setCallsite("Wallpaper#relayout")
+ .build();
+ }
Surface blastSurface = getOrCreateBLASTSurface(mSurfaceSize.x,
mSurfaceSize.y, mFormat);
// If blastSurface == null that means it hasn't changed since the last
@@ -987,11 +997,6 @@
}
if (!mLastSurfaceSize.equals(mSurfaceSize)) {
mLastSurfaceSize.set(mSurfaceSize.x, mSurfaceSize.y);
- if (mSurfaceControl != null && mSurfaceControl.isValid()) {
- SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- t.setBufferSize(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y);
- t.apply();
- }
}
if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
@@ -1830,6 +1835,14 @@
} catch (RemoteException e) {
}
mSurfaceHolder.mSurface.release();
+ if (mBlastBufferQueue != null) {
+ mBlastBufferQueue.destroy();
+ mBlastBufferQueue = null;
+ }
+ if (mBbqSurfaceControl != null) {
+ new SurfaceControl.Transaction().remove(mBbqSurfaceControl).apply();
+ mBbqSurfaceControl = null;
+ }
mCreated = false;
}
}
@@ -1854,13 +1867,13 @@
private Surface getOrCreateBLASTSurface(int width, int height, int format) {
Surface ret = null;
if (mBlastBufferQueue == null) {
- mBlastBufferQueue = new BLASTBufferQueue("Wallpaper", mSurfaceControl, width,
- height, format);
+ mBlastBufferQueue = new BLASTBufferQueue("Wallpaper", mBbqSurfaceControl,
+ width, height, format);
// We only return the Surface the first time, as otherwise
// it hasn't changed and there is no need to update.
ret = mBlastBufferQueue.createSurface();
} else {
- mBlastBufferQueue.update(mSurfaceControl, width, height, format);
+ mBlastBufferQueue.update(mBbqSurfaceControl, width, height, format);
}
return ret;
diff --git a/core/java/android/speech/IRecognitionService.aidl b/core/java/android/speech/IRecognitionService.aidl
index 9a5e534..cc349c8 100644
--- a/core/java/android/speech/IRecognitionService.aidl
+++ b/core/java/android/speech/IRecognitionService.aidl
@@ -58,7 +58,6 @@
* Cancels the speech recognition.
*
* @param listener to receive callbacks, note that this must be non-null
- * @param packageName the package name calling this API
*/
void cancel(in IRecognitionListener listener, boolean isShutdown);
}
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index ad670c8..bb48757 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -34,7 +34,6 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
-import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
@@ -66,7 +65,12 @@
private static final String TAG = "RecognitionService";
/** Debugging flag */
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
+
+ private static final String RECORD_AUDIO_APP_OP =
+ AppOpsManager.permissionToOp(Manifest.permission.RECORD_AUDIO);
+ private static final int RECORD_AUDIO_APP_OP_CODE =
+ AppOpsManager.permissionToOpCode(Manifest.permission.RECORD_AUDIO);
/** Binder of the recognition service */
private RecognitionServiceBinder mBinder = new RecognitionServiceBinder(this);
@@ -97,7 +101,7 @@
dispatchStopListening((IRecognitionListener) msg.obj);
break;
case MSG_CANCEL:
- dispatchCancel((IRecognitionListener) msg.obj, msg.arg1 == 1);
+ dispatchCancel((IRecognitionListener) msg.obj);
break;
case MSG_RESET:
dispatchClearCallback();
@@ -108,18 +112,20 @@
private void dispatchStartListening(Intent intent, final IRecognitionListener listener,
@NonNull AttributionSource attributionSource) {
- if (mCurrentCallback == null) {
- if (DBG) Log.d(TAG, "created new mCurrentCallback, listener = " + listener.asBinder());
- mCurrentCallback = new Callback(listener, attributionSource);
+ try {
+ if (mCurrentCallback == null) {
+ if (DBG) {
+ Log.d(TAG, "created new mCurrentCallback, listener = " + listener.asBinder());
+ }
+ mCurrentCallback = new Callback(listener, attributionSource);
- RecognitionService.this.onStartListening(intent, mCurrentCallback);
- } else {
- try {
+ RecognitionService.this.onStartListening(intent, mCurrentCallback);
+ } else {
listener.onError(SpeechRecognizer.ERROR_RECOGNIZER_BUSY);
- } catch (RemoteException e) {
- Log.d(TAG, "onError call from startListening failed");
+ Log.i(TAG, "concurrent startListening received - ignoring this call");
}
- Log.i(TAG, "concurrent startListening received - ignoring this call");
+ } catch (RemoteException e) {
+ Log.d(TAG, "onError call from startListening failed");
}
}
@@ -139,16 +145,13 @@
}
}
- private void dispatchCancel(IRecognitionListener listener, boolean shutDown) {
+ private void dispatchCancel(IRecognitionListener listener) {
if (mCurrentCallback == null) {
if (DBG) Log.d(TAG, "cancel called with no preceding startListening - ignoring");
} else if (mCurrentCallback.mListener.asBinder() != listener.asBinder()) {
Log.w(TAG, "cancel called by client who did not call startListening - ignoring");
} else { // the correct state
RecognitionService.this.onCancel(mCurrentCallback);
- if (shutDown) {
- mCurrentCallback.finishRecordAudioOpAttributionToCallerIfNeeded();
- }
mCurrentCallback = null;
if (DBG) Log.d(TAG, "canceling - setting mCurrentCallback to null");
}
@@ -173,47 +176,6 @@
}
/**
- * Checks whether the caller has sufficient permissions
- *
- * @param listener to send the error message to in case of error
- * @param forDataDelivery If the permission check is for delivering the sensitive data.
- * @param packageName the package name of the caller
- * @param featureId The feature in the package
- * @return {@code true} if the caller has enough permissions, {@code false} otherwise
- */
- private boolean checkPermissions(IRecognitionListener listener, boolean forDataDelivery,
- @NonNull String packageName, @Nullable String featureId) {
- if (DBG) Log.d(TAG, "checkPermissions");
-
- final int callingUid = Binder.getCallingUid();
- if (callingUid == Process.SYSTEM_UID) {
- // Assuming system has verified permissions of the caller.
- return true;
- }
-
- if (forDataDelivery) {
- if (PermissionChecker.checkCallingOrSelfPermissionForDataDelivery(this,
- android.Manifest.permission.RECORD_AUDIO, packageName, featureId,
- null /*message*/) == PermissionChecker.PERMISSION_GRANTED) {
- return true;
- }
- } else {
- if (PermissionChecker.checkCallingOrSelfPermissionForPreflight(this,
- android.Manifest.permission.RECORD_AUDIO)
- == PermissionChecker.PERMISSION_GRANTED) {
- return true;
- }
- }
- try {
- Log.e(TAG, "call for recognition service without RECORD_AUDIO permissions");
- listener.onError(SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS);
- } catch (RemoteException re) {
- Log.e(TAG, "sending ERROR_INSUFFICIENT_PERMISSIONS message failed", re);
- }
- return false;
- }
-
- /**
* Notifies the service that it should start listening for speech.
*
* @param recognizerIntent contains parameters for the recognition to be performed. The intent
@@ -281,7 +243,6 @@
* single channel audio stream. The sample rate is implementation dependent.
*/
public void bufferReceived(byte[] buffer) throws RemoteException {
- startRecordAudioOpAttributionToCallerIfNeeded();
mListener.onBufferReceived(buffer);
}
@@ -314,7 +275,6 @@
* {@link SpeechRecognizer#RESULTS_RECOGNITION} as a parameter
*/
public void partialResults(Bundle partialResults) throws RemoteException {
- startRecordAudioOpAttributionToCallerIfNeeded();
mListener.onPartialResults(partialResults);
}
@@ -336,7 +296,6 @@
* {@link SpeechRecognizer#RESULTS_RECOGNITION} as a parameter
*/
public void results(Bundle results) throws RemoteException {
- startRecordAudioOpAttributionToCallerIfNeeded();
Message.obtain(mHandler, MSG_RESET).sendToTarget();
mListener.onResults(results);
}
@@ -366,9 +325,6 @@
* and passing this identity to {@link
* android.content.ContextParams.Builder#setNextAttributionSource(AttributionSource)}.
*
- *
- *
- *
* @return The permission identity of the calling app.
*
* @see android.content.ContextParams.Builder#setNextAttributionSource(
@@ -379,40 +335,55 @@
return mCallingAttributionSource;
}
- private void startRecordAudioOpAttributionToCallerIfNeeded() throws RemoteException {
- if (!isProxyingRecordAudioToCaller()) {
- final int result = PermissionChecker.checkPermissionAndStartDataDelivery(
- RecognitionService.this, Manifest.permission.RECORD_AUDIO,
- getAttributionContextForCaller().getAttributionSource(),
- /*message*/ null);
- if (result == PermissionChecker.PERMISSION_GRANTED) {
- return;
- }
- error(SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS);
+ boolean maybeStartAttribution() {
+ if (DBG) {
+ Log.i(TAG, "Starting attribution");
}
- }
- private @NonNull Context getAttributionContextForCaller() {
- if (mAttributionContext == null) {
+ if (DBG && isProxyingRecordAudioToCaller()) {
+ Log.i(TAG, "Proxying already in progress, not starting the attribution");
+ }
+
+ if (!isProxyingRecordAudioToCaller()) {
mAttributionContext = createContext(new ContextParams.Builder()
.setNextAttributionSource(mCallingAttributionSource)
.build());
+
+ final int result = PermissionChecker.checkPermissionAndStartDataDelivery(
+ RecognitionService.this,
+ Manifest.permission.RECORD_AUDIO,
+ mAttributionContext.getAttributionSource(),
+ /*message*/ null);
+
+ return result == PermissionChecker.PERMISSION_GRANTED;
}
- return mAttributionContext;
+ return false;
}
- void finishRecordAudioOpAttributionToCallerIfNeeded() {
+ void maybeFinishAttribution() {
+ if (DBG) {
+ Log.i(TAG, "Finishing attribution");
+ }
+
+ if (DBG && !isProxyingRecordAudioToCaller()) {
+ Log.i(TAG, "Not proxying currently, not finishing the attribution");
+ }
+
if (isProxyingRecordAudioToCaller()) {
- final String op = AppOpsManager.permissionToOp(Manifest.permission.RECORD_AUDIO);
- PermissionChecker.finishDataDelivery(RecognitionService.this,
- op, getAttributionContextForCaller().getAttributionSource());
+ PermissionChecker.finishDataDelivery(
+ RecognitionService.this,
+ RECORD_AUDIO_APP_OP,
+ mAttributionContext.getAttributionSource());
+
+ mAttributionContext = null;
}
}
private boolean isProxyingRecordAudioToCaller() {
- final int op = AppOpsManager.permissionToOpCode(Manifest.permission.RECORD_AUDIO);
final AppOpsManager appOpsManager = getSystemService(AppOpsManager.class);
- return appOpsManager.isProxying(op, getAttributionTag(),
+ return appOpsManager.isProxying(
+ RECORD_AUDIO_APP_OP_CODE,
+ getAttributionTag(),
mCallingAttributionSource.getUid(),
mCallingAttributionSource.getPackageName());
}
@@ -423,7 +394,7 @@
private final WeakReference<RecognitionService> mServiceRef;
public RecognitionServiceBinder(RecognitionService service) {
- mServiceRef = new WeakReference<RecognitionService>(service);
+ mServiceRef = new WeakReference<>(service);
}
@Override
@@ -445,8 +416,8 @@
if (DBG) Log.d(TAG, "stopListening called by:" + listener.asBinder());
final RecognitionService service = mServiceRef.get();
if (service != null) {
- service.mHandler.sendMessage(Message.obtain(service.mHandler,
- MSG_STOP_LISTENING, listener));
+ service.mHandler.sendMessage(
+ Message.obtain(service.mHandler, MSG_STOP_LISTENING, listener));
}
}
@@ -455,8 +426,8 @@
if (DBG) Log.d(TAG, "cancel called by:" + listener.asBinder());
final RecognitionService service = mServiceRef.get();
if (service != null) {
- service.mHandler.sendMessage(Message.obtain(service.mHandler,
- MSG_CANCEL, isShutdown ? 1 : 0, 0, listener));
+ service.mHandler.sendMessage(
+ Message.obtain(service.mHandler, MSG_CANCEL, listener));
}
}
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index 22ccd23..3183f15 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -43,7 +43,7 @@
/**
* The extra key used in an intent which is providing an already opened audio source for the
- * RecognitionService to use.
+ * RecognitionService to use. Data should be a URI to an audio resource.
*/
public static final String EXTRA_AUDIO_INJECT_SOURCE =
"android.speech.extra.AUDIO_INJECT_SOURCE";
diff --git a/core/java/android/uwb/AdapterStateListener.java b/core/java/android/uwb/AdapterStateListener.java
index b990095..91847f7 100644
--- a/core/java/android/uwb/AdapterStateListener.java
+++ b/core/java/android/uwb/AdapterStateListener.java
@@ -68,8 +68,7 @@
mIsRegistered = true;
} catch (RemoteException e) {
Log.w(TAG, "Failed to register adapter state callback");
- executor.execute(() -> callback.onStateChanged(mAdapterState,
- AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN));
+ throw e.rethrowFromSystemServer();
}
} else {
sendCurrentState(callback);
@@ -95,6 +94,7 @@
mAdapter.unregisterAdapterStateCallbacks(this);
} catch (RemoteException e) {
Log.w(TAG, "Failed to unregister AdapterStateCallback with service");
+ throw e.rethrowFromSystemServer();
}
mIsRegistered = false;
}
@@ -115,24 +115,24 @@
mAdapter.setEnabled(isEnabled);
} catch (RemoteException e) {
Log.w(TAG, "Failed to set adapter state");
- sendErrorState();
+ throw e.rethrowFromSystemServer();
}
}
}
}
- private void sendErrorState() {
+ /**
+ * Gets the adapter enabled state
+ *
+ * @return integer representing adapter enabled state
+ */
+ public int getAdapterState() {
synchronized (this) {
- for (AdapterStateCallback callback: mCallbackMap.keySet()) {
- Executor executor = mCallbackMap.get(callback);
-
- final long identity = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> callback.onStateChanged(
- mAdapterState, mAdapterStateChangeReason));
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ try {
+ return mAdapter.getAdapterState();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get adapter state");
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl
index 29021c1..d879350 100644
--- a/core/java/android/uwb/IUwbAdapter.aidl
+++ b/core/java/android/uwb/IUwbAdapter.aidl
@@ -161,6 +161,18 @@
*/
void setEnabled(boolean enabled);
+ /**
+ * Returns the current enabled/disabled UWB state.
+ *
+ * Possible values are:
+ * IUwbAdapterState#STATE_DISABLED
+ * IUwbAdapterState#STATE_ENABLED_ACTIVE
+ * IUwbAdapterState#STATE_ENABLED_INACTIVE
+ *
+ * @return value representing enabled/disabled UWB state.
+ */
+ int getAdapterState();
+
/**
* The maximum allowed time to open a ranging session.
*/
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index 3c99f89..f7406ae 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -178,7 +178,7 @@
* <p>The provided callback will be invoked by the given {@link Executor}.
*
* <p>When first registering a callback, the callbacks's
- * {@link AdapterStateCallback#onStateChanged(boolean, int)} is immediately invoked to indicate
+ * {@link AdapterStateCallback#onStateChanged(int, int)} is immediately invoked to indicate
* the current state of the underlying UWB adapter with the most recent
* {@link AdapterStateCallback.StateChangedReason} that caused the change.
*
@@ -279,6 +279,21 @@
}
/**
+ * Returns the current enabled/disabled state for UWB.
+ *
+ * Possible values are:
+ * AdapterStateCallback#STATE_DISABLED
+ * AdapterStateCallback#STATE_ENABLED_INACTIVE
+ * AdapterStateCallback#STATE_ENABLED_ACTIVE
+ *
+ * @return value representing current enabled/disabled state for UWB.
+ * @hide
+ */
+ public @AdapterStateCallback.State int getAdapterState() {
+ return mAdapterStateListener.getAdapterState();
+ }
+
+ /**
* Disables or enables UWB for a user
*
* @param enabled value representing intent to disable or enable UWB. If true any subsequent
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index c87db65..9cb0d1f 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -17,6 +17,7 @@
package android.view;
import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_MODE;
+import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -36,6 +37,7 @@
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
+import android.hardware.display.BrightnessInfo;
import android.hardware.display.DeviceProductInfo;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
@@ -730,6 +732,15 @@
}
/**
+ * @return Brightness information about the display.
+ * @hide
+ */
+ @RequiresPermission(CONTROL_DISPLAY_BRIGHTNESS)
+ public @Nullable BrightnessInfo getBrightnessInfo() {
+ return mGlobal.getBrightnessInfo(mDisplayId);
+ }
+
+ /**
* Gets the size of the display, in pixels.
* Value returned by this method does not necessarily represent the actual raw size
* (native resolution) of the display.
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 88406ff..cd82489 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -857,7 +857,5 @@
*/
void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener);
- void setForceCrossWindowBlurDisabled(boolean disable);
-
boolean isTaskSnapshotSupported();
}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index aa3c9d6..ff2d2eb 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -936,18 +936,21 @@
* @param frameRate The intended frame rate of this surface, in frames per second. 0
* is a special value that indicates the app will accept the system's choice for the
* display frame rate, which is the default behavior if this function isn't
- * called. The frameRate param does <em>not</em> need to be a valid refresh rate for
- * this device's display - e.g., it's fine to pass 30fps to a device that can only run
+ * called. The <code>frameRate</code> parameter does <em>not</em> need to be a valid refresh
+ * rate for this device's display - e.g., it's fine to pass 30fps to a device that can only run
* the display at 60fps.
*
* @param compatibility The frame rate compatibility of this surface. The
* compatibility value may influence the system's choice of display frame rate.
+ * This parameter is ignored when <code>frameRate</code> is 0.
*
- * @param changeFrameRateStrategy Whether display refresh rate transitions should be seamless. A
- * seamless transition is one that doesn't have any visual interruptions, such as a black
- * screen for a second or two.
+ * @param changeFrameRateStrategy Whether display refresh rate transitions caused by this
+ * surface should be seamless. A seamless transition is one that doesn't have any visual
+ * interruptions, such as a black screen for a second or two. This parameter is ignored when
+ * <code>frameRate</code> is 0.
*
- * @throws IllegalArgumentException If frameRate or compatibility are invalid.
+ * @throws IllegalArgumentException If <code>frameRate</code>, <code>compatibility</code> or
+ * <code>changeFrameRateStrategy</code> are invalid.
*/
public void setFrameRate(@FloatRange(from = 0.0) float frameRate,
@FrameRateCompatibility int compatibility,
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 3ff7a65..ac70dff 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -3298,20 +3298,26 @@
* because the system may change the display refresh rate, calls to this function may result
* in changes to Choreographer callback timings, and changes to the time interval at which
* the system releases buffers back to the application.
+ * <p>
+ * Note that this only has an effect for surfaces presented on the display. If this
+ * surface is consumed by something other than the system compositor, e.g. a media
+ * codec, this call has no effect.
*
* @param sc The SurfaceControl to specify the frame rate of.
* @param frameRate The intended frame rate for this surface, in frames per second. 0 is a
* special value that indicates the app will accept the system's choice for
* the display frame rate, which is the default behavior if this function
- * isn't called. The frameRate param does <em>not</em> need to be a valid
- * refresh rate for this device's display - e.g., it's fine to pass 30fps
- * to a device that can only run the display at 60fps.
+ * isn't called. The <code>frameRate</code> param does <em>not</em> need
+ * to be a valid refresh rate for this device's display - e.g., it's fine
+ * to pass 30fps to a device that can only run the display at 60fps.
* @param compatibility The frame rate compatibility of this surface. The compatibility
* value may influence the system's choice of display frame rate.
- * @param changeFrameRateStrategy Whether display refresh rate transitions should be
- * seamless. A seamless transition is one that doesn't have
- * any visual interruptions, such as a black screen for a
- * second or two.
+ * This parameter is ignored when <code>frameRate</code> is 0.
+ * @param changeFrameRateStrategy Whether display refresh rate transitions caused by this
+ * surface should be seamless. A seamless transition is one
+ * that doesn't have any visual interruptions, such as a
+ * black screen for a second or two. This parameter is
+ * ignored when <code>frameRate</code> is 0.
* @return This transaction object.
*/
@NonNull
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b2df3a9..11fac05 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4003,6 +4003,16 @@
/**
* @hide
+ *
+ * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+ * out of the public fields to keep the undefined bits out of the developer's way.
+ *
+ * Flag to disable the ongoing call chip.
+ */
+ public static final int STATUS_BAR_DISABLE_ONGOING_CALL_CHIP = 0x04000000;
+
+ /**
+ * @hide
*/
public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7;
@@ -4227,7 +4237,10 @@
name = "STATUS_BAR_DISABLE_RECENT"),
@ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH,
equals = STATUS_BAR_DISABLE_SEARCH,
- name = "STATUS_BAR_DISABLE_SEARCH")
+ name = "STATUS_BAR_DISABLE_SEARCH"),
+ @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP,
+ equals = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP,
+ name = "STATUS_BAR_DISABLE_ONGOING_CALL_CHIP")
}, formatToHexString = true)
@SystemUiVisibility
int mSystemUiVisibility;
@@ -4256,6 +4269,7 @@
STATUS_BAR_DISABLE_CLOCK,
STATUS_BAR_DISABLE_RECENT,
STATUS_BAR_DISABLE_SEARCH,
+ STATUS_BAR_DISABLE_ONGOING_CALL_CHIP,
})
@Retention(RetentionPolicy.SOURCE)
public @interface SystemUiVisibility {}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 60516eb..c32ab3a 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -908,20 +908,6 @@
}
/**
- * Disables cross-window blurs device-wide. This includes window blur behind
- * (see {@link LayoutParams#setBlurBehindRadius}) and window background blur
- * (see {@link Window#setBackgroundBlurRadius}).
- *
- * @param disable specifies whether to disable the blur. Note that calling this
- * with 'disable=false' will not enable blurs if there is something
- * else disabling blurs.
- * @hide
- */
- @TestApi
- default void setForceCrossWindowBlurDisabled(boolean disable) {
- }
-
- /**
* @hide
*/
static String transitTypeToString(@TransitionType int type) {
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 07eeb03..f8009919 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -328,15 +328,6 @@
}
@Override
- public void setForceCrossWindowBlurDisabled(boolean disable) {
- try {
- WindowManagerGlobal.getWindowManagerService()
- .setForceCrossWindowBlurDisabled(disable);
- } catch (RemoteException e) {
- }
- }
-
- @Override
public boolean isTaskSnapshotSupported() {
try {
return WindowManagerGlobal.getWindowManagerService().isTaskSnapshotSupported();
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index d6292ca..b4c1dd2 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -93,6 +93,7 @@
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
import com.android.internal.inputmethod.ResultCallbacks;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.inputmethod.StartInputFlags;
import com.android.internal.inputmethod.StartInputReason;
import com.android.internal.inputmethod.UnbindReason;
@@ -266,6 +267,14 @@
private static final int NOT_A_SUBTYPE_ID = -1;
/**
+ * {@code true} to try to avoid blocking apps' UI thread by sending
+ * {@link StartInputReason#WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION} and
+ * {@link StartInputReason#WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION} in a truly asynchronous
+ * way. {@code false} to go back to the previous synchronous semantics.
+ */
+ private static final boolean USE_REPORT_WINDOW_GAINED_FOCUS_ASYNC = true;
+
+ /**
* A constant that represents Voice IME.
*
* @see InputMethodSubtype#getMode()
@@ -689,20 +698,29 @@
Log.v(TAG, "Reporting focus gain, without startInput"
+ ", nextFocusIsServedView=" + nextFocusHasConnection);
}
- final int startInputReason =
- nextFocusHasConnection ? WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION
- : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
- final Completable.InputBindResult value = Completable.createInputBindResult();
- mService.startInputOrWindowGainedFocus(
- startInputReason, mClient,
- focusedView.getWindowToken(), startInputFlags, softInputMode,
- windowFlags,
- null,
- null,
- 0 /* missingMethodFlags */,
- mCurRootView.mContext.getApplicationInfo().targetSdkVersion,
- ResultCallbacks.of(value));
- Completable.getResult(value); // ignore the result
+
+ if (USE_REPORT_WINDOW_GAINED_FOCUS_ASYNC) {
+ mService.reportWindowGainedFocusAsync(
+ nextFocusHasConnection, mClient, focusedView.getWindowToken(),
+ startInputFlags, softInputMode, windowFlags,
+ mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
+ } else {
+ final int startInputReason = nextFocusHasConnection
+ ? WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION
+ : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
+ final Completable.InputBindResult value =
+ Completable.createInputBindResult();
+ mService.startInputOrWindowGainedFocus(
+ startInputReason, mClient,
+ focusedView.getWindowToken(), startInputFlags, softInputMode,
+ windowFlags,
+ null,
+ null,
+ 0 /* missingMethodFlags */,
+ mCurRootView.mContext.getApplicationInfo().targetSdkVersion,
+ ResultCallbacks.of(value));
+ Completable.getResult(value); // ignore the result
+ }
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1087,6 +1105,11 @@
public void setImeTraceEnabled(boolean enabled) {
ImeTracing.getInstance().setEnabled(enabled);
}
+
+ @Override
+ public void throwExceptionFromSystem(String message) {
+ throw new RuntimeException(message);
+ }
};
final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
@@ -1674,6 +1697,11 @@
* {@link #RESULT_HIDDEN}.
*/
public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
+ return showSoftInput(view, flags, resultReceiver, SoftInputShowHideReason.SHOW_SOFT_INPUT);
+ }
+
+ private boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver,
+ @SoftInputShowHideReason int reason) {
ImeTracing.getInstance().triggerClientDump("InputMethodManager#showSoftInput", this,
null /* icProto */);
// Re-dispatch if there is a context mismatch.
@@ -1690,13 +1718,15 @@
}
try {
- Log.d(TAG, "showSoftInput() view=" + view + " flags=" + flags);
+ Log.d(TAG, "showSoftInput() view=" + view + " flags=" + flags + " reason="
+ + InputMethodDebug.softInputDisplayReasonToString(reason));
final Completable.Boolean value = Completable.createBoolean();
mService.showSoftInput(
mClient,
view.getWindowToken(),
flags,
resultReceiver,
+ reason,
ResultCallbacks.of(value));
return Completable.getResult(value);
} catch (RemoteException e) {
@@ -1731,6 +1761,7 @@
mCurRootView.getView().getWindowToken(),
flags,
resultReceiver,
+ SoftInputShowHideReason.SHOW_SOFT_INPUT,
ResultCallbacks.of(value));
Completable.getResult(value); // ignore the result
} catch (RemoteException e) {
@@ -1795,6 +1826,12 @@
*/
public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
ResultReceiver resultReceiver) {
+ return hideSoftInputFromWindow(windowToken, flags, resultReceiver,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT);
+ }
+
+ private boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
+ ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromWindow",
this, null /* icProto */);
checkFocus();
@@ -1806,8 +1843,8 @@
try {
final Completable.Boolean value = Completable.createBoolean();
- mService.hideSoftInput(
- mClient, windowToken, flags, resultReceiver, ResultCallbacks.of(value));
+ mService.hideSoftInput(mClient, windowToken, flags, resultReceiver, reason,
+ ResultCallbacks.of(value));
return Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1827,7 +1864,14 @@
* @param hideFlags Provides additional operating flags. May be
* 0 or have the {@link #HIDE_IMPLICIT_ONLY},
* {@link #HIDE_NOT_ALWAYS} bit set.
- **/
+ *
+ * @deprecated Use {@link #showSoftInput(View, int)} or
+ * {@link #hideSoftInputFromWindow(IBinder, int)} explicitly instead.
+ * In particular during focus changes, the current visibility of the IME is not
+ * well defined. Starting in {@link Build.VERSION_CODES#S Android S}, this only
+ * has an effect if the calling app is the current IME focus.
+ */
+ @Deprecated
public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) {
ImeTracing.getInstance().triggerClientDump(
"InputMethodManager#toggleSoftInputFromWindow", InputMethodManager.this,
@@ -1837,9 +1881,7 @@
if (servedView == null || servedView.getWindowToken() != windowToken) {
return;
}
- if (mCurrentInputMethodSession != null) {
- mCurrentInputMethodSession.toggleSoftInput(showFlags, hideFlags);
- }
+ toggleSoftInput(showFlags, hideFlags);
}
}
@@ -1854,13 +1896,29 @@
* @param hideFlags Provides additional operating flags. May be
* 0 or have the {@link #HIDE_IMPLICIT_ONLY},
* {@link #HIDE_NOT_ALWAYS} bit set.
+ *
+ * @deprecated Use {@link #showSoftInput(View, int)} or
+ * {@link #hideSoftInputFromWindow(IBinder, int)} explicitly instead.
+ * In particular during focus changes, the current visibility of the IME is not
+ * well defined. Starting in {@link Build.VERSION_CODES#S Android S}, this only
+ * has an effect if the calling app is the current IME focus.
*/
+ @Deprecated
public void toggleSoftInput(int showFlags, int hideFlags) {
ImeTracing.getInstance().triggerClientDump(
"InputMethodManager#toggleSoftInput", InputMethodManager.this,
null /* icProto */);
- if (mCurrentInputMethodSession != null) {
- mCurrentInputMethodSession.toggleSoftInput(showFlags, hideFlags);
+ synchronized (mH) {
+ final View view = getServedViewLocked();
+ if (mImeInsetsConsumer != null && view != null) {
+ if (mImeInsetsConsumer.isRequestedVisible()) {
+ hideSoftInputFromWindow(view.getWindowToken(), hideFlags, null,
+ SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT);
+ } else {
+ showSoftInput(view, showFlags, null,
+ SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT);
+ }
+ }
}
}
@@ -2144,6 +2202,7 @@
mCurRootView.getView().getWindowToken(),
HIDE_NOT_ALWAYS,
null,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT,
ResultCallbacks.of(value));
Completable.getResult(value); // ignore the result
} catch (RemoteException e) {
diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java
index 0d688ff..52c1cd4f 100644
--- a/core/java/android/view/inputmethod/InputMethodSession.java
+++ b/core/java/android/view/inputmethod/InputMethodSession.java
@@ -17,6 +17,8 @@
package android.view.inputmethod;
import android.graphics.Rect;
+import android.inputmethodservice.InputMethodService;
+import android.os.Build;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -172,7 +174,13 @@
* @param hideFlags Provides additional operating flags. May be
* 0 or have the {@link InputMethodManager#HIDE_IMPLICIT_ONLY},
* {@link InputMethodManager#HIDE_NOT_ALWAYS} bit set.
+ *
+ * @deprecated Starting in {@link Build.VERSION_CODES#S} the system no longer invokes this
+ * method, instead it explicitly shows or hides the IME. An {@code InputMethodService}
+ * wishing to toggle its own visibility should instead invoke {@link
+ * InputMethodService#requestShowSelf} or {@link InputMethodService#requestHideSelf}
*/
+ @Deprecated
public void toggleSoftInput(int showFlags, int hideFlags);
/**
diff --git a/core/java/android/view/inputmethod/InputMethodSessionWrapper.java b/core/java/android/view/inputmethod/InputMethodSessionWrapper.java
index c4a3773..ef1814b 100644
--- a/core/java/android/view/inputmethod/InputMethodSessionWrapper.java
+++ b/core/java/android/view/inputmethod/InputMethodSessionWrapper.java
@@ -96,15 +96,6 @@
}
@AnyThread
- void toggleSoftInput(int showFlags, int hideFlags) {
- try {
- mSession.toggleSoftInput(showFlags, hideFlags);
- } catch (RemoteException e) {
- Log.w(TAG, "IME died", e);
- }
- }
-
- @AnyThread
void appPrivateCommand(String action, Bundle data) {
try {
mSession.appPrivateCommand(action, data);
diff --git a/core/java/android/view/translation/ITranslationManager.aidl b/core/java/android/view/translation/ITranslationManager.aidl
index 560edec..5fbf228 100644
--- a/core/java/android/view/translation/ITranslationManager.aidl
+++ b/core/java/android/view/translation/ITranslationManager.aidl
@@ -22,6 +22,7 @@
import android.view.autofill.AutofillId;
import android.view.translation.TranslationContext;
import android.view.translation.TranslationSpec;
+import android.view.translation.UiTranslationSpec;
import com.android.internal.os.IResultReceiver;
import java.util.List;
@@ -34,12 +35,14 @@
oneway interface ITranslationManager {
void onTranslationCapabilitiesRequest(int sourceFormat, int destFormat,
in ResultReceiver receiver, int userId);
+ void registerTranslationCapabilityCallback(in IRemoteCallback callback, int userId);
+ void unregisterTranslationCapabilityCallback(in IRemoteCallback callback, int userId);
void onSessionCreated(in TranslationContext translationContext,
int sessionId, in IResultReceiver receiver, int userId);
void updateUiTranslationState(int state, in TranslationSpec sourceSpec,
in TranslationSpec targetSpec, in List<AutofillId> viewIds, IBinder token, int taskId,
- int userId);
+ in UiTranslationSpec uiTranslationSpec, int userId);
void registerUiTranslationStateCallback(in IRemoteCallback callback, int userId);
void unregisterUiTranslationStateCallback(in IRemoteCallback callback, int userId);
diff --git a/core/java/android/view/translation/TranslationManager.java b/core/java/android/view/translation/TranslationManager.java
index 52790f6..20d817d 100644
--- a/core/java/android/view/translation/TranslationManager.java
+++ b/core/java/android/view/translation/TranslationManager.java
@@ -16,6 +16,7 @@
package android.view.translation;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
@@ -41,12 +42,14 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
/**
* The {@link TranslationManager} class provides ways for apps to integrate and use the
@@ -81,11 +84,14 @@
*/
public static final String EXTRA_CAPABILITIES = "translation_capabilities";
- // TODO: implement update listeners and propagate updates.
@GuardedBy("mLock")
private final ArrayMap<Pair<Integer, Integer>, ArrayList<PendingIntent>>
mTranslationCapabilityUpdateListeners = new ArrayMap<>();
+ @GuardedBy("mLock")
+ private final Map<Consumer<TranslationCapability>, IRemoteCallback> mCapabilityCallbacks =
+ new ArrayMap<>();
+
private static final Random ID_GENERATOR = new Random();
private final Object mLock = new Object();
@@ -94,10 +100,6 @@
private final ITranslationManager mService;
- @Nullable
- @GuardedBy("mLock")
- private ITranslationDirectManager mDirectServiceBinder;
-
@NonNull
@GuardedBy("mLock")
private final SparseArray<Translator> mTranslators = new SparseArray<>();
@@ -125,11 +127,72 @@
/**
* Creates an on-device Translator for natural language translation.
*
+ * @param translationContext {@link TranslationContext} containing the specs for creating the
+ * Translator.
+ * @param executor Executor to run callback operations
+ * @param callback {@link Consumer} to receive the translator. A {@code null} value is returned
+ * if the service could not create the translator.
+ */
+ public void createOnDeviceTranslator(@NonNull TranslationContext translationContext,
+ @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Translator> callback) {
+ Objects.requireNonNull(translationContext, "translationContext cannot be null");
+ Objects.requireNonNull(executor, "executor cannot be null");
+ Objects.requireNonNull(callback, "callback cannot be null");
+
+ synchronized (mLock) {
+ // TODO(b/176464808): Disallow multiple Translator now, it will throw
+ // IllegalStateException. Need to discuss if we can allow multiple Translators.
+ if (mTranslatorIds.containsKey(translationContext)) {
+ executor.execute(() -> callback.accept(
+ mTranslators.get(mTranslatorIds.get(translationContext))));
+ return;
+ }
+
+ int translatorId;
+ do {
+ translatorId = Math.abs(ID_GENERATOR.nextInt());
+ } while (translatorId == 0 || mTranslators.indexOfKey(translatorId) >= 0);
+ final int tId = translatorId;
+
+ new Translator(mContext, translationContext, translatorId, this, mHandler, mService,
+ new Consumer<Translator>() {
+ @Override
+ public void accept(Translator translator) {
+ if (translator == null) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.accept(null));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return;
+ }
+
+ mTranslators.put(tId, translator);
+ mTranslatorIds.put(translationContext, tId);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.accept(translator));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Creates an on-device Translator for natural language translation.
+ *
* <p><strong>NOTE: </strong>Call on a worker thread.
*
+ * @deprecated use {@link #createOnDeviceTranslator(TranslationContext, Executor, Consumer)}
+ * instead.
+ *
* @param translationContext {@link TranslationContext} containing the specs for creating the
* Translator.
*/
+ @Deprecated
@Nullable
@WorkerThread
public Translator createOnDeviceTranslator(@NonNull TranslationContext translationContext) {
@@ -232,17 +295,43 @@
}
/**
- * Registers a {@link PendingIntent} to listen for updates on states of on-device
+ * Adds a {@link TranslationCapability} Consumer to listen for updates on states of on-device
* {@link TranslationCapability}s.
*
- * <p>IMPORTANT: the pending intent must be called to start a service, or a broadcast if it is
- * an explicit intent.</p>
- *
- * @param sourceFormat data format for the input data to be translated.
- * @param targetFormat data format for the expected translated output data.
- * @param pendingIntent the pending intent to invoke when updates are received.
+ * @param capabilityListener a {@link TranslationCapability} Consumer to receive the updated
+ * {@link TranslationCapability} from the on-device translation service.
*/
public void addOnDeviceTranslationCapabilityUpdateListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<TranslationCapability> capabilityListener) {
+ Objects.requireNonNull(executor, "executor should not be null");
+ Objects.requireNonNull(capabilityListener, "capability listener should not be null");
+
+ synchronized (mLock) {
+ if (mCapabilityCallbacks.containsKey(capabilityListener)) {
+ Log.w(TAG, "addOnDeviceTranslationCapabilityUpdateListener: the listener for "
+ + capabilityListener + " already registered; ignoring.");
+ return;
+ }
+ final IRemoteCallback remoteCallback = new TranslationCapabilityRemoteCallback(executor,
+ capabilityListener);
+ try {
+ mService.registerTranslationCapabilityCallback(remoteCallback,
+ mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ mCapabilityCallbacks.put(capabilityListener, remoteCallback);
+ }
+ }
+
+
+ /**
+ * @deprecated Use {@link TranslationManager#addOnDeviceTranslationCapabilityUpdateListener(
+ * java.util.concurrent.Executor, java.util.function.Consumer)}
+ */
+ @Deprecated
+ public void addOnDeviceTranslationCapabilityUpdateListener(
@TranslationSpec.DataFormat int sourceFormat,
@TranslationSpec.DataFormat int targetFormat,
@NonNull PendingIntent pendingIntent) {
@@ -256,8 +345,8 @@
}
/**
- * @deprecated Use {@link #addOnDeviceTranslationCapabilityUpdateListener(int, int,
- * PendingIntent)}
+ * @deprecated Use {@link TranslationManager#addOnDeviceTranslationCapabilityUpdateListener(
+ * java.util.concurrent.Executor, java.util.function.Consumer)}
*/
@Deprecated
public void addTranslationCapabilityUpdateListener(
@@ -268,14 +357,38 @@
}
/**
- * Unregisters a {@link PendingIntent} to listen for updates on states of on-device
- * {@link TranslationCapability}s.
+ * Removes a {@link TranslationCapability} Consumer to listen for updates on states of
+ * on-device {@link TranslationCapability}s.
*
- * @param sourceFormat data format for the input data to be translated.
- * @param targetFormat data format for the expected translated output data.
- * @param pendingIntent the pending intent to unregister
+ * @param capabilityListener the {@link TranslationCapability} Consumer to unregister
*/
public void removeOnDeviceTranslationCapabilityUpdateListener(
+ @NonNull Consumer<TranslationCapability> capabilityListener) {
+ Objects.requireNonNull(capabilityListener, "capability callback should not be null");
+
+ synchronized (mLock) {
+ final IRemoteCallback remoteCallback = mCapabilityCallbacks.get(capabilityListener);
+ if (remoteCallback == null) {
+ Log.w(TAG, "removeOnDeviceTranslationCapabilityUpdateListener: the capability "
+ + "listener not found; ignoring.");
+ return;
+ }
+ try {
+ mService.unregisterTranslationCapabilityCallback(remoteCallback,
+ mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ mCapabilityCallbacks.remove(capabilityListener);
+ }
+ }
+
+ /**
+ * @deprecated Use {@link #removeOnDeviceTranslationCapabilityUpdateListener(
+ * java.util.function.Consumer)}.
+ */
+ @Deprecated
+ public void removeOnDeviceTranslationCapabilityUpdateListener(
@TranslationSpec.DataFormat int sourceFormat,
@TranslationSpec.DataFormat int targetFormat,
@NonNull PendingIntent pendingIntent) {
@@ -300,8 +413,8 @@
}
/**
- * @deprecated Use {@link #removeOnDeviceTranslationCapabilityUpdateListener(int, int,
- * PendingIntent)}
+ * @deprecated Use {@link #removeOnDeviceTranslationCapabilityUpdateListener(
+ * java.util.function.Consumer)}.
*/
@Deprecated
public void removeTranslationCapabilityUpdateListener(
@@ -366,9 +479,12 @@
private static class TranslationCapabilityRemoteCallback extends
IRemoteCallback.Stub {
private final Executor mExecutor;
+ private final Consumer<TranslationCapability> mListener;
- TranslationCapabilityRemoteCallback(Executor executor) {
+ TranslationCapabilityRemoteCallback(Executor executor,
+ Consumer<TranslationCapability> listener) {
mExecutor = executor;
+ mListener = listener;
}
@Override
@@ -378,9 +494,9 @@
}
private void onTranslationCapabilityUpdate(Bundle bundle) {
- TranslationCapability capability = (TranslationCapability) bundle.getParcelable(
- EXTRA_CAPABILITIES);
- //TODO: Implement after deciding how capability listeners are implemented.
+ TranslationCapability capability =
+ (TranslationCapability) bundle.getParcelable(EXTRA_CAPABILITIES);
+ mListener.accept(capability);
}
}
}
diff --git a/core/java/android/view/translation/Translator.java b/core/java/android/view/translation/Translator.java
index 6037302..b0d95b3 100644
--- a/core/java/android/view/translation/Translator.java
+++ b/core/java/android/view/translation/Translator.java
@@ -101,10 +101,18 @@
public static final String EXTRA_SESSION_ID = "sessionId";
static class ServiceBinderReceiver extends IResultReceiver.Stub {
+ // TODO: refactor how translator is instantiated after removing deprecated createTranslator.
private final WeakReference<Translator> mTranslator;
private final CountDownLatch mLatch = new CountDownLatch(1);
private int mSessionId;
+ private Consumer<Translator> mCallback;
+
+ ServiceBinderReceiver(Translator translator, Consumer<Translator> callback) {
+ mTranslator = new WeakReference<>(translator);
+ mCallback = callback;
+ }
+
ServiceBinderReceiver(Translator translator) {
mTranslator = new WeakReference<>(translator);
}
@@ -126,6 +134,9 @@
public void send(int resultCode, Bundle resultData) {
if (resultCode == STATUS_SYNC_CALL_FAIL) {
mLatch.countDown();
+ if (mCallback != null) {
+ mCallback.accept(null);
+ }
return;
}
mSessionId = resultData.getInt(EXTRA_SESSION_ID);
@@ -146,6 +157,9 @@
}
translator.setServiceBinder(binder);
mLatch.countDown();
+ if (mCallback != null) {
+ mCallback.accept(translator);
+ }
}
// TODO(b/176464808): maybe make SyncResultReceiver.TimeoutException constructor public
@@ -165,6 +179,32 @@
public Translator(@NonNull Context context,
@NonNull TranslationContext translationContext, int sessionId,
@NonNull TranslationManager translationManager, @NonNull Handler handler,
+ @Nullable ITranslationManager systemServerBinder,
+ @NonNull Consumer<Translator> callback) {
+ mContext = context;
+ mTranslationContext = translationContext;
+ mId = sessionId;
+ mManager = translationManager;
+ mHandler = handler;
+ mSystemServerBinder = systemServerBinder;
+ mServiceBinderReceiver = new ServiceBinderReceiver(this, callback);
+
+ try {
+ mSystemServerBinder.onSessionCreated(mTranslationContext, mId,
+ mServiceBinderReceiver, mContext.getUserId());
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException calling startSession(): " + e);
+ }
+ }
+
+ /**
+ * Create the Translator.
+ *
+ * @hide
+ */
+ public Translator(@NonNull Context context,
+ @NonNull TranslationContext translationContext, int sessionId,
+ @NonNull TranslationManager translationManager, @NonNull Handler handler,
@Nullable ITranslationManager systemServerBinder) {
mContext = context;
mTranslationContext = translationContext;
diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java
index eefc7fd..541b494 100644
--- a/core/java/android/view/translation/UiTranslationManager.java
+++ b/core/java/android/view/translation/UiTranslationManager.java
@@ -119,15 +119,31 @@
}
/**
+ * @deprecated Use {@link #startTranslation(TranslationSpec, TranslationSpec, List, ActivityId,
+ * UiTranslationSpec)} instead.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+ @Deprecated
+ @SystemApi
+ public void startTranslation(@NonNull TranslationSpec sourceSpec,
+ @NonNull TranslationSpec targetSpec, @NonNull List<AutofillId> viewIds,
+ @NonNull ActivityId activityId) {
+ startTranslation(
+ sourceSpec, targetSpec, viewIds, activityId,
+ new UiTranslationSpec.Builder().setShouldPadContentForCompat(true).build());
+ }
+
+ /**
* Request ui translation for a given Views.
*
* @param sourceSpec {@link TranslationSpec} for the data to be translated.
* @param targetSpec {@link TranslationSpec} for the translated data.
* @param viewIds A list of the {@link View}'s {@link AutofillId} which needs to be translated
* @param activityId the identifier for the Activity which needs ui translation
+ * @param uiTranslationSpec configuration for translation of the specified views
* @throws IllegalArgumentException if the no {@link View}'s {@link AutofillId} in the list
- * @throws NullPointerException the sourceSpec, targetSpec, viewIds, activityId or
- * {@link android.app.assist.ActivityId#getToken()} is {@code null}
*
* @hide
*/
@@ -135,19 +151,21 @@
@SystemApi
public void startTranslation(@NonNull TranslationSpec sourceSpec,
@NonNull TranslationSpec targetSpec, @NonNull List<AutofillId> viewIds,
- @NonNull ActivityId activityId) {
+ @NonNull ActivityId activityId, @NonNull UiTranslationSpec uiTranslationSpec) {
// TODO(b/177789967): Return result code or find a way to notify the status.
Objects.requireNonNull(sourceSpec);
Objects.requireNonNull(targetSpec);
Objects.requireNonNull(viewIds);
Objects.requireNonNull(activityId);
Objects.requireNonNull(activityId.getToken());
+ Objects.requireNonNull(uiTranslationSpec);
if (viewIds.size() == 0) {
throw new IllegalArgumentException("Invalid empty views: " + viewIds);
}
try {
mService.updateUiTranslationState(STATE_UI_TRANSLATION_STARTED, sourceSpec,
targetSpec, viewIds, activityId.getToken(), activityId.getTaskId(),
+ uiTranslationSpec,
mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -172,7 +190,8 @@
Objects.requireNonNull(activityId.getToken());
mService.updateUiTranslationState(STATE_UI_TRANSLATION_FINISHED,
null /* sourceSpec */, null /* targetSpec */, null /* viewIds */,
- activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
+ activityId.getToken(), activityId.getTaskId(), null /* uiTranslationSpec */,
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -196,7 +215,8 @@
Objects.requireNonNull(activityId.getToken());
mService.updateUiTranslationState(STATE_UI_TRANSLATION_PAUSED,
null /* sourceSpec */, null /* targetSpec */, null /* viewIds */,
- activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
+ activityId.getToken(), activityId.getTaskId(), null /* uiTranslationSpec */,
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -220,7 +240,8 @@
Objects.requireNonNull(activityId.getToken());
mService.updateUiTranslationState(STATE_UI_TRANSLATION_RESUMED,
null /* sourceSpec */, null /* targetSpec */, null /* viewIds */,
- activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
+ activityId.getToken(), activityId.getTaskId(), null /* uiTranslationSpec */,
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/telephony/java/android/telephony/ims/RcsConfig.aidl b/core/java/android/view/translation/UiTranslationSpec.aidl
similarity index 82%
copy from telephony/java/android/telephony/ims/RcsConfig.aidl
copy to core/java/android/view/translation/UiTranslationSpec.aidl
index cfd93fb..7fbeb66 100644
--- a/telephony/java/android/telephony/ims/RcsConfig.aidl
+++ b/core/java/android/view/translation/UiTranslationSpec.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.telephony.ims;
+package android.view.translation;
-parcelable RcsConfig;
+parcelable UiTranslationSpec;
diff --git a/core/java/android/view/translation/UiTranslationSpec.java b/core/java/android/view/translation/UiTranslationSpec.java
new file mode 100644
index 0000000..b43dbce
--- /dev/null
+++ b/core/java/android/view/translation/UiTranslationSpec.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.translation;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Specifications for configuring UI translation.
+ *
+ * @hide
+ */
+@DataClass(
+ genBuilder = true, genEqualsHashCode = true, genHiddenConstDefs = true, genToString = true)
+@DataClass.Suppress("isShouldPadContentForCompat")
+@SystemApi
+public final class UiTranslationSpec implements Parcelable {
+
+ /**
+ * Whether the original content of the view should be directly modified to include padding that
+ * makes it the same size as the translated content. Defaults to {@code false}.
+ * <p>
+ * For {@link android.widget.TextView}, the system does not directly modify the original text,
+ * rather changes the displayed content using a
+ * {@link android.text.method.TransformationMethod}.
+ * This can cause issues in apps that do not account for TransformationMethods. For example, an
+ * app using DynamicLayout may use the calculated text offsets to operate on the original text,
+ * but this can be problematic when the layout was calculated on translated text with a
+ * different length.
+ * <p>
+ * If this is {@code true}, for a TextView the default implementation will append spaces to the
+ * text to make the length the same as the translated text.
+ */
+ private boolean mShouldPadContentForCompat = false;
+
+ /**
+ * Whether the original content of the view should be directly modified to include padding that
+ * makes it the same size as the translated content.
+ * <p>
+ * For {@link android.widget.TextView}, the system does not directly modify the original text,
+ * rather changes the displayed content using a
+ * {@link android.text.method.TransformationMethod}.
+ * This can cause issues in apps that do not account for TransformationMethods. For example, an
+ * app using DynamicLayout may use the calculated text offsets to operate on the original text,
+ * but this can be problematic when the layout was calculated on translated text with a
+ * different length.
+ * <p>
+ * If this is {@code true}, for a TextView the default implementation will append spaces to the
+ * text to make the length the same as the translated text.
+ */
+ public boolean shouldPadContentForCompat() {
+ return mShouldPadContentForCompat;
+ }
+
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/translation/UiTranslationSpec.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @DataClass.Generated.Member
+ /* package-private */ UiTranslationSpec(
+ boolean shouldPadContentForCompat) {
+ this.mShouldPadContentForCompat = shouldPadContentForCompat;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "UiTranslationSpec { " +
+ "shouldPadContentForCompat = " + mShouldPadContentForCompat +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public boolean equals(@android.annotation.Nullable Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(UiTranslationSpec other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ UiTranslationSpec that = (UiTranslationSpec) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && mShouldPadContentForCompat == that.mShouldPadContentForCompat;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int hashCode() {
+ // You can override field hashCode logic by defining methods like:
+ // int fieldNameHashCode() { ... }
+
+ int _hash = 1;
+ _hash = 31 * _hash + Boolean.hashCode(mShouldPadContentForCompat);
+ return _hash;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ byte flg = 0;
+ if (mShouldPadContentForCompat) flg |= 0x1;
+ dest.writeByte(flg);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ UiTranslationSpec(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ byte flg = in.readByte();
+ boolean shouldPadContentForCompat = (flg & 0x1) != 0;
+
+ this.mShouldPadContentForCompat = shouldPadContentForCompat;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<UiTranslationSpec> CREATOR
+ = new Parcelable.Creator<UiTranslationSpec>() {
+ @Override
+ public UiTranslationSpec[] newArray(int size) {
+ return new UiTranslationSpec[size];
+ }
+
+ @Override
+ public UiTranslationSpec createFromParcel(@NonNull Parcel in) {
+ return new UiTranslationSpec(in);
+ }
+ };
+
+ /**
+ * A builder for {@link UiTranslationSpec}
+ */
+ @SuppressWarnings("WeakerAccess")
+ @DataClass.Generated.Member
+ public static final class Builder {
+
+ private boolean mShouldPadContentForCompat;
+
+ private long mBuilderFieldsSet = 0L;
+
+ public Builder() {
+ }
+
+ /**
+ * Whether the original content of the view should be directly modified to include padding that
+ * makes it the same size as the translated content. Defaults to {@code false}.
+ * <p>
+ * For {@link android.widget.TextView}, the system does not directly modify the original text,
+ * rather changes the displayed content using a
+ * {@link android.text.method.TransformationMethod}.
+ * This can cause issues in apps that do not account for TransformationMethods. For example, an
+ * app using DynamicLayout may use the calculated text offsets to operate on the original text,
+ * but this can be problematic when the layout was calculated on translated text with a
+ * different length.
+ * <p>
+ * If this is {@code true}, for a TextView the default implementation will append spaces to the
+ * text to make the length the same as the translated text.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setShouldPadContentForCompat(boolean value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x1;
+ mShouldPadContentForCompat = value;
+ return this;
+ }
+
+ /** Builds the instance. This builder should not be touched after calling this! */
+ public @NonNull UiTranslationSpec build() {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x2; // Mark builder used
+
+ if ((mBuilderFieldsSet & 0x1) == 0) {
+ mShouldPadContentForCompat = false;
+ }
+ UiTranslationSpec o = new UiTranslationSpec(
+ mShouldPadContentForCompat);
+ return o;
+ }
+
+ private void checkNotUsed() {
+ if ((mBuilderFieldsSet & 0x2) != 0) {
+ throw new IllegalStateException(
+ "This Builder should not be reused. Use a new Builder instance instead");
+ }
+ }
+ }
+
+ @DataClass.Generated(
+ time = 1619034161701L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/core/java/android/view/translation/UiTranslationSpec.java",
+ inputSignatures = "private boolean mShouldPadContentForCompat\npublic boolean shouldPadContentForCompat()\nclass UiTranslationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genToString=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 18dd799..33890b8 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -939,6 +939,7 @@
// The surface we allocate for the magnifier content + shadow.
private final SurfaceSession mSurfaceSession;
private final SurfaceControl mSurfaceControl;
+ private final SurfaceControl mBbqSurfaceControl;
private final BLASTBufferQueue mBBQ;
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
private final Surface mSurface;
@@ -1008,11 +1009,19 @@
mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
.setName("magnifier surface")
.setFlags(SurfaceControl.HIDDEN)
- .setBLASTLayer()
+ .setContainerLayer()
.setParent(parentSurfaceControl)
.setCallsite("InternalPopupWindow")
.build();
- mBBQ = new BLASTBufferQueue("magnifier surface", mSurfaceControl,
+ mBbqSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
+ .setName("magnifier surface bbq wrapper")
+ .setHidden(false)
+ .setBLASTLayer()
+ .setParent(mSurfaceControl)
+ .setCallsite("InternalPopupWindow")
+ .build();
+
+ mBBQ = new BLASTBufferQueue("magnifier surface", mBbqSurfaceControl,
surfaceWidth, surfaceHeight, PixelFormat.TRANSLUCENT);
mSurface = mBBQ.createSurface();
@@ -1073,7 +1082,7 @@
}
if (mContentHeight < contentHeight) {
// Grows the surface height as necessary.
- mBBQ.update(mSurfaceControl, mContentWidth, contentHeight,
+ mBBQ.update(mBbqSurfaceControl, mContentWidth, contentHeight,
PixelFormat.TRANSLUCENT);
mRenderer.setSurface(mSurface);
@@ -1270,7 +1279,10 @@
mRenderer.destroy();
mSurface.destroy();
mBBQ.destroy();
- new SurfaceControl.Transaction().remove(mSurfaceControl).apply();
+ new SurfaceControl.Transaction()
+ .remove(mSurfaceControl)
+ .remove(mBbqSurfaceControl)
+ .apply();
mSurfaceSession.kill();
mHandler.removeCallbacks(mMagnifierUpdater);
if (mBitmap != null) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index e47129e..0dbdb8f6 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1226,6 +1226,7 @@
return rect;
}
+ @Nullable
private static Class<?> getParameterType(int type) {
switch (type) {
case BaseReflectionAction.BOOLEAN:
@@ -1267,6 +1268,7 @@
}
}
+ @Nullable
private MethodHandle getMethod(View view, String methodName, Class<?> paramType,
boolean async) {
MethodArgs result;
@@ -1517,6 +1519,7 @@
}
}
+ @Nullable
public Bitmap getBitmapForId(int id) {
if (id == -1 || id >= mBitmaps.size()) {
return null;
@@ -1864,8 +1867,9 @@
}
}
+ @Nullable
@Override
- protected Object getParameterValue(View view) throws ActionException {
+ protected Object getParameterValue(@Nullable View view) throws ActionException {
return this.value;
}
@@ -1904,8 +1908,11 @@
dest.writeInt(this.mResId);
}
+ @Nullable
@Override
- protected Object getParameterValue(View view) throws ActionException {
+ protected Object getParameterValue(@Nullable View view) throws ActionException {
+ if (view == null) return null;
+
Resources resources = view.getContext().getResources();
try {
switch (this.mResourceType) {
@@ -2079,8 +2086,11 @@
dest.writeInt(this.mUnit);
}
+ @Nullable
@Override
- protected Object getParameterValue(View view) throws ActionException {
+ protected Object getParameterValue(@Nullable View view) throws ActionException {
+ if (view == null) return null;
+
DisplayMetrics dm = view.getContext().getResources().getDisplayMetrics();
try {
int data = TypedValue.createComplexDimension(this.mValue, this.mUnit);
@@ -3592,6 +3602,9 @@
while (remoteViews.hasNext()) {
RemoteViews view = remoteViews.next();
SizeF size = view.getIdealSize();
+ if (size == null) {
+ throw new IllegalStateException("Expected RemoteViews to have ideal size");
+ }
float newViewArea = size.getWidth() * size.getHeight();
if (smallestView != null && !view.hasSameAppInfo(smallestView.mApplication)) {
throw new IllegalArgumentException(
@@ -5309,6 +5322,10 @@
float bestSqDist = Float.MAX_VALUE;
for (RemoteViews layout : mSizedRemoteViews) {
SizeF layoutSize = layout.getIdealSize();
+ if (layoutSize == null) {
+ throw new IllegalStateException("Expected RemoteViews to have ideal size");
+ }
+
if (fitsIn(layoutSize, widgetSize)) {
if (bestFit == null) {
bestFit = layout;
@@ -5342,7 +5359,7 @@
*/
public RemoteViews getRemoteViewsToApply(@NonNull Context context,
@Nullable SizeF widgetSize) {
- if (!hasSizedRemoteViews()) {
+ if (!hasSizedRemoteViews() || widgetSize == null) {
// If there isn't multiple remote views, fall back on the previous methods.
return getRemoteViewsToApply(context);
}
@@ -5419,7 +5436,7 @@
/** @hide */
public View apply(Context context, ViewGroup parent, InteractionHandler handler,
- @NonNull SizeF size, @Nullable ColorResources colorResources) {
+ @Nullable SizeF size, @Nullable ColorResources colorResources) {
RemoteViews rvToApply = getRemoteViewsToApply(context, size);
View result = inflateView(context, rvToApply, parent, 0, colorResources);
@@ -5431,7 +5448,7 @@
return inflateView(context, rv, parent, 0, null);
}
- private View inflateView(Context context, RemoteViews rv, ViewGroup parent,
+ private View inflateView(Context context, RemoteViews rv, @Nullable ViewGroup parent,
@StyleRes int applyThemeResId, @Nullable ColorResources colorResources) {
// RemoteViews may be built by an application installed in another
// user. So build a context that loads resources from that user but
@@ -5447,8 +5464,7 @@
if (applyThemeResId != 0) {
inflationContext = new ContextThemeWrapper(inflationContext, applyThemeResId);
}
- LayoutInflater inflater = (LayoutInflater)
- context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ LayoutInflater inflater = LayoutInflater.from(context);
// Clone inflater so we load resources from correct context and
// we don't add a filter to the static version returned by getSystemService.
@@ -5576,6 +5592,7 @@
mResult = result;
}
+ @Nullable
@Override
protected ViewTree doInBackground(Void... params) {
try {
@@ -5860,6 +5877,7 @@
* are in an array, the array's entries are 16 bytes each. We use this to work out the
* location of all the positions of the various resources.
*/
+ @Nullable
private static byte[] createCompiledResourcesContent(Context context,
SparseIntArray colorResources) throws IOException {
byte[] content;
@@ -5897,6 +5915,7 @@
*
* @hide
*/
+ @Nullable
public static ColorResources create(Context context, SparseIntArray colorMapping) {
try {
byte[] contentBytes = createCompiledResourcesContent(context, colorMapping);
@@ -6020,7 +6039,8 @@
}
}
- private static ApplicationInfo getApplicationInfo(String packageName, int userId) {
+ @Nullable
+ private static ApplicationInfo getApplicationInfo(@Nullable String packageName, int userId) {
if (packageName == null) {
return null;
}
@@ -6096,6 +6116,7 @@
}
}
+ @Nullable
public ViewTree findViewTreeById(@IdRes int id) {
if (mRoot.getId() == id) {
return this;
@@ -6112,6 +6133,7 @@
return null;
}
+ @Nullable
public ViewTree findViewTreeParentOf(ViewTree child) {
if (mChildren == null) {
return null;
@@ -6134,6 +6156,7 @@
createTree();
}
+ @Nullable
public <T extends View> T findViewById(@IdRes int id) {
if (mChildren == null) {
return mRoot.findViewById(id);
@@ -6391,6 +6414,8 @@
*/
@Nullable
private static AdapterView<?> getAdapterViewAncestor(@Nullable View view) {
+ if (view == null) return null;
+
View parent = (View) view.getParent();
// Break the for loop on the first encounter of:
// 1) an AdapterView,
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index a16c151..7c04b1c 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -461,7 +461,7 @@
@Override
public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results) {
final Editable editable = (Editable) mTextView.getText();
-
+ final int sentenceLength = editable.length();
for (int i = 0; i < results.length; ++i) {
final SentenceSuggestionsInfo ssi = results[i];
if (ssi == null) {
@@ -475,6 +475,9 @@
}
final int offset = ssi.getOffsetAt(j);
final int length = ssi.getLengthAt(j);
+ if (offset < 0 || offset + length > sentenceLength) {
+ continue;
+ }
final SpellCheckSpan scs = onGetSuggestionsInternal(
suggestionsInfo, offset, length);
if (spellCheckSpan == null && scs != null) {
diff --git a/core/java/android/window/SplashScreen.java b/core/java/android/window/SplashScreen.java
index 18f29ae..7d222db 100644
--- a/core/java/android/window/SplashScreen.java
+++ b/core/java/android/window/SplashScreen.java
@@ -17,12 +17,17 @@
package android.window;
import android.annotation.NonNull;
+import android.annotation.StyleRes;
import android.annotation.SuppressLint;
import android.annotation.UiThread;
import android.app.Activity;
import android.app.ActivityThread;
+import android.app.AppGlobals;
import android.content.Context;
+import android.content.res.Resources;
import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
import android.util.Singleton;
import android.util.Slog;
@@ -60,6 +65,17 @@
*/
void clearOnExitAnimationListener();
+
+ /**
+ * Overrides the theme used for the {@link SplashScreen}s of this application.
+ * <p>
+ * By default, the {@link SplashScreen} uses the theme set in the manifest. This method
+ * overrides and persists the theme used for the {@link SplashScreen} of this application.
+ * <p>
+ * To reset to the default theme, set this the themeId to {@link Resources#ID_NULL}.
+ */
+ void setSplashScreenTheme(@StyleRes int themeId);
+
/**
* Listens for the splash screen exit event.
*/
@@ -84,6 +100,8 @@
* @hide
*/
class SplashScreenImpl implements SplashScreen {
+ private static final String TAG = "SplashScreenImpl";
+
private OnExitAnimationListener mExitAnimationListener;
private final IBinder mActivityToken;
private final SplashScreenManagerGlobal mGlobal;
@@ -119,6 +137,29 @@
mGlobal.removeImpl(this);
}
}
+
+ public void setSplashScreenTheme(@StyleRes int themeId) {
+ if (mActivityToken == null) {
+ Log.w(TAG, "Couldn't persist the starting theme. This instance is not an Activity");
+ return;
+ }
+
+ Activity activity = ActivityThread.currentActivityThread().getActivity(
+ mActivityToken);
+ if (activity == null) {
+ return;
+ }
+ String themeName = themeId != Resources.ID_NULL
+ ? activity.getResources().getResourceName(themeId) : null;
+
+ try {
+ AppGlobals.getPackageManager().setSplashScreenTheme(
+ activity.getComponentName().getPackageName(),
+ themeName, activity.getUserId());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Couldn't persist the starting theme", e);
+ }
+ }
}
/**
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 26a6f0d..c0af572 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -109,8 +109,8 @@
}
/**
- * Notify activities within the hierarchy of a container that they have entered picture-in-picture
- * mode with the given bounds.
+ * Notify {@link com.android.server.wm.PinnedTaskController} that the picture-in-picture task
+ * has finished the enter animation with the given bounds.
*/
@NonNull
public WindowContainerTransaction scheduleFinishEnterPip(
@@ -339,6 +339,33 @@
}
/**
+ * Sets the container as launch adjacent flag root. Task starting with
+ * {@link FLAG_ACTIVITY_LAUNCH_ADJACENT} will be launching to.
+ *
+ * @hide
+ */
+ @NonNull
+ public WindowContainerTransaction setLaunchAdjacentFlagRoot(
+ @NonNull WindowContainerToken container) {
+ mHierarchyOps.add(HierarchyOp.createForSetLaunchAdjacentFlagRoot(container.asBinder(),
+ false /* clearRoot */));
+ return this;
+ }
+
+ /**
+ * Clears launch adjacent flag root for the display area of passing container.
+ *
+ * @hide
+ */
+ @NonNull
+ public WindowContainerTransaction clearLaunchAdjacentFlagRoot(
+ @NonNull WindowContainerToken container) {
+ mHierarchyOps.add(HierarchyOp.createForSetLaunchAdjacentFlagRoot(container.asBinder(),
+ true /* clearRoot */));
+ return this;
+ }
+
+ /**
* Starts a task by id. The task is expected to already exist (eg. as a recent task).
* @param taskId Id of task to start.
* @param options bundle containing ActivityOptions for the task's top activity.
@@ -677,6 +704,7 @@
public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT = 3;
public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS = 4;
public static final int HIERARCHY_OP_TYPE_LAUNCH_TASK = 5;
+ public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT = 6;
// The following key(s) are for use with mLaunchOptions:
// When launching a task (eg. from recents), this is the taskId to be launched.
@@ -734,6 +762,14 @@
fullOptions);
}
+ /** Create a hierarchy op for setting launch adjacent flag root. */
+ public static HierarchyOp createForSetLaunchAdjacentFlagRoot(IBinder container,
+ boolean clearRoot) {
+ return new HierarchyOp(HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT, container, null,
+ null, null, clearRoot, null);
+ }
+
+
private HierarchyOp(int type, @Nullable IBinder container, @Nullable IBinder reparent,
int[] windowingModes, int[] activityTypes, boolean toTop,
@Nullable Bundle launchOptions) {
@@ -829,6 +865,9 @@
+ " adjacentRoot=" + mReparent + "}";
case HIERARCHY_OP_TYPE_LAUNCH_TASK:
return "{LaunchTask: " + mLaunchOptions + "}";
+ case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT:
+ return "{SetAdjacentFlagRoot: container=" + mContainer + " clearRoot=" + mToTop
+ + "}";
default:
return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
+ " mToTop=" + mToTop + " mWindowingMode=" + mWindowingModes
diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java
index 375e503..f34aabb 100644
--- a/core/java/com/android/internal/app/NetInitiatedActivity.java
+++ b/core/java/com/android/internal/app/NetInitiatedActivity.java
@@ -16,6 +16,8 @@
package com.android.internal.app;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
@@ -69,6 +71,8 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+
// Set up the "dialog"
final Intent intent = getIntent();
final AlertController.AlertParams p = mAlertParams;
diff --git a/core/java/com/android/internal/colorextraction/OWNERS b/core/java/com/android/internal/colorextraction/OWNERS
new file mode 100644
index 0000000..ffade1e
--- /dev/null
+++ b/core/java/com/android/internal/colorextraction/OWNERS
@@ -0,0 +1,3 @@
+dupin@google.com
+cinek@google.com
+jamesoleary@google.com
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index efce0a84..06f68e8 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -81,6 +81,12 @@
public static final String SCREENSHOT_NOTIFICATION_SMART_ACTIONS_TIMEOUT_MS =
"screenshot_notification_smart_actions_timeout_ms";
+ /**
+ * (int) Timeout value in ms to get Quick Share actions for screenshot notification.
+ */
+ public static final String SCREENSHOT_NOTIFICATION_QUICK_SHARE_ACTIONS_TIMEOUT_MS =
+ "screenshot_notification_quick_share_actions_timeout_ms";
+
// Flags related to Smart Suggestions - these are read in SmartReplyConstants.
/** (boolean) Whether to enable smart suggestions in notifications. */
diff --git a/core/java/com/android/internal/display/BrightnessSynchronizer.java b/core/java/com/android/internal/display/BrightnessSynchronizer.java
index 6776c27..bd90890 100644
--- a/core/java/com/android/internal/display/BrightnessSynchronizer.java
+++ b/core/java/com/android/internal/display/BrightnessSynchronizer.java
@@ -16,11 +16,11 @@
package com.android.internal.display;
-
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
@@ -95,7 +95,7 @@
}
final BrightnessSyncObserver brightnessSyncObserver;
- brightnessSyncObserver = new BrightnessSyncObserver(mHandler);
+ brightnessSyncObserver = new BrightnessSyncObserver();
brightnessSyncObserver.startObserving();
final float currentFloatBrightness = getScreenBrightnessFloat();
@@ -232,47 +232,52 @@
}
}
- private class BrightnessSyncObserver extends ContentObserver {
- /**
- * Creates a content observer.
- * @param handler The handler to run {@link #onChange} on, or null if none.
- */
- BrightnessSyncObserver(Handler handler) {
- super(handler);
- }
+ private class BrightnessSyncObserver {
+ private final DisplayListener mListener = new DisplayListener() {
+ @Override
+ public void onDisplayAdded(int displayId) {}
- @Override
- public void onChange(boolean selfChange) {
- onChange(selfChange, null);
- }
+ @Override
+ public void onDisplayRemoved(int displayId) {}
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- if (selfChange) {
- return;
- }
- if (BRIGHTNESS_URI.equals(uri)) {
- int currentBrightness = getScreenBrightnessInt(mContext);
- mHandler.removeMessages(MSG_UPDATE_FLOAT);
- mHandler.obtainMessage(MSG_UPDATE_FLOAT, currentBrightness, 0).sendToTarget();
- } else if (BRIGHTNESS_FLOAT_URI.equals(uri)) {
+ @Override
+ public void onDisplayChanged(int displayId) {
float currentFloat = getScreenBrightnessFloat();
int toSend = Float.floatToIntBits(currentFloat);
mHandler.removeMessages(MSG_UPDATE_INT);
mHandler.obtainMessage(MSG_UPDATE_INT, toSend, 0).sendToTarget();
}
- }
+ };
+
+ private final ContentObserver mContentObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (selfChange) {
+ return;
+ }
+ if (BRIGHTNESS_URI.equals(uri)) {
+ int currentBrightness = getScreenBrightnessInt(mContext);
+ mHandler.removeMessages(MSG_UPDATE_FLOAT);
+ mHandler.obtainMessage(MSG_UPDATE_FLOAT, currentBrightness, 0).sendToTarget();
+ }
+ }
+ };
public void startObserving() {
final ContentResolver cr = mContext.getContentResolver();
- cr.unregisterContentObserver(this);
- cr.registerContentObserver(BRIGHTNESS_URI, false, this, UserHandle.USER_ALL);
- cr.registerContentObserver(BRIGHTNESS_FLOAT_URI, false, this, UserHandle.USER_ALL);
+ cr.unregisterContentObserver(mContentObserver);
+ cr.registerContentObserver(BRIGHTNESS_URI, false, mContentObserver,
+ UserHandle.USER_ALL);
+
+ mDisplayManager.registerDisplayListener(mListener, mHandler,
+ DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+ | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS);
}
public void stopObserving() {
final ContentResolver cr = mContext.getContentResolver();
- cr.unregisterContentObserver(this);
+ cr.unregisterContentObserver(mContentObserver);
+ mDisplayManager.unregisterDisplayListener(mListener);
}
}
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index 93374ba..d026ecd 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -230,6 +230,10 @@
return "HIDE_REMOVE_CLIENT";
case SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY:
return "SHOW_RESTORE_IME_VISIBILITY";
+ case SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT:
+ return "SHOW_TOGGLE_SOFT_INPUT";
+ case SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT:
+ return "HIDE_TOGGLE_SOFT_INPUT";
default:
return "Unknown=" + reason;
}
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index f1cdf2b..755bd5e 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -50,7 +50,9 @@
SoftInputShowHideReason.HIDE_BUBBLES,
SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR,
SoftInputShowHideReason.HIDE_REMOVE_CLIENT,
- SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY})
+ SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY,
+ SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT,
+ SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT})
public @interface SoftInputShowHideReason {
/** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
int SHOW_SOFT_INPUT = 0;
@@ -174,4 +176,16 @@
* {@link com.android.server.wm.WindowManagerInternal#shouldRestoreImeVisibility}.
*/
int SHOW_RESTORE_IME_VISIBILITY = 22;
+
+ /**
+ * Show soft input by
+ * {@link android.view.inputmethod.InputMethodManager#toggleSoftInput(int, int)};
+ */
+ int SHOW_TOGGLE_SOFT_INPUT = 23;
+
+ /**
+ * Hide soft input by
+ * {@link android.view.inputmethod.InputMethodManager#toggleSoftInput(int, int)};
+ */
+ int HIDE_TOGGLE_SOFT_INPUT = 24;
}
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 135c076..4d3f774 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -102,6 +102,7 @@
private boolean mMetricsFinalized;
private boolean mCancelled = false;
private FrameTrackerListener mListener;
+ private boolean mTracingStarted = false;
private static class JankInfo {
long frameVsyncId;
@@ -207,7 +208,15 @@
public synchronized void begin() {
mBeginVsyncId = mChoreographer.getVsyncId() + 1;
mSession.setTimeStamp(System.nanoTime());
- Trace.beginAsyncSection(mSession.getName(), (int) mBeginVsyncId);
+ mChoreographer.mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, () -> {
+ synchronized (FrameTracker.this) {
+ if (mCancelled || mEndVsyncId != INVALID_ID) {
+ return;
+ }
+ mTracingStarted = true;
+ Trace.beginAsyncSection(mSession.getName(), (int) mBeginVsyncId);
+ }
+ }, null);
mRendererWrapper.addObserver(mObserver);
if (DEBUG) {
Log.d(TAG, "begin: " + mSession.getName() + ", begin=" + mBeginVsyncId);
@@ -255,7 +264,7 @@
*/
public synchronized void cancel(@Reasons int reason) {
// We don't need to end the trace section if it never begun.
- if (mBeginVsyncId != INVALID_ID) {
+ if (mTracingStarted) {
Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
}
mCancelled = true;
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 5ab2a82..0441594 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -79,6 +79,12 @@
/**
* This class let users to begin and end the always on tracing mechanism.
+ *
+ * Enabling for local development:
+ *
+ * adb shell device_config put interaction_jank_monitor enabled true
+ * adb shell device_config put interaction_jank_monitor sampling_interval 1
+ *
* @hide
*/
public class InteractionJankMonitor {
diff --git a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
index aa416c5..73d962e 100644
--- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
+++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
@@ -53,7 +53,7 @@
builder.getOrCreateSystemBatteryConsumerBuilder(
SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN, powerMah, powerModel)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN, durationMs);
+ .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN, durationMs);
}
/**
diff --git a/core/java/com/android/internal/os/AudioPowerCalculator.java b/core/java/com/android/internal/os/AudioPowerCalculator.java
index 79b331d..9da8191 100644
--- a/core/java/com/android/internal/os/AudioPowerCalculator.java
+++ b/core/java/com/android/internal/os/AudioPowerCalculator.java
@@ -42,7 +42,7 @@
final long durationMs = mPowerEstimator.calculateDuration(u.getAudioTurnedOnTimer(),
rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
final double powerMah = mPowerEstimator.calculatePower(durationMs);
- app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO, durationMs)
+ app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO, powerMah);
}
}
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index 9ad7c15..babcea1 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -124,16 +124,11 @@
final long realtimeUs = elapsedRealtime() * 1000;
final long uptimeUs = uptimeMillis() * 1000;
- final String[] customPowerComponentNames = mStats.getCustomEnergyConsumerNames();
-
- // TODO(b/174186358): read extra time component number from configuration
- final int customTimeComponentCount = 0;
-
final boolean includePowerModels = (query.getFlags()
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
final BatteryUsageStats.Builder batteryUsageStatsBuilder = new BatteryUsageStats.Builder(
- customPowerComponentNames, customTimeComponentCount, includePowerModels);
+ mStats.getCustomEnergyConsumerNames(), includePowerModels);
batteryUsageStatsBuilder.setStatsStartTimestamp(mStats.getStartClockTime());
SparseArray<? extends BatteryStats.Uid> uidStats = mStats.getUidStats();
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 30a3536..7ecf69b 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -57,7 +57,7 @@
public static final boolean DEFAULT_TRACK_SCREEN_INTERACTIVE = false;
public static final boolean DEFAULT_TRACK_DIRECT_CALLING_UID = true;
public static final boolean DEFAULT_IGNORE_BATTERY_STATUS = false;
- public static final boolean DEFAULT_COLLECT_LATENCY_DATA = false;
+ public static final boolean DEFAULT_COLLECT_LATENCY_DATA = true;
public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 1500;
private static final String DEBUG_ENTRY_PREFIX = "__DEBUG_";
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
index a418dff..2c32e48 100644
--- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -88,7 +88,7 @@
+ " power=" + formatCharge(systemPowerMah));
}
systemBatteryConsumerBuilder
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH,
+ .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
systemComponentDurationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
Math.max(systemPowerMah, total.powerMah), powerModel)
@@ -105,7 +105,7 @@
final long durationMs = calculateDuration(activityCounter);
final double powerMah = calculatePowerMah(powerModel, measuredChargeUC, activityCounter);
- app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH, durationMs)
+ app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, powerMah, powerModel);
total.durationMs += durationMs;
diff --git a/core/java/com/android/internal/os/CameraPowerCalculator.java b/core/java/com/android/internal/os/CameraPowerCalculator.java
index 6f8e927..e56e7be 100644
--- a/core/java/com/android/internal/os/CameraPowerCalculator.java
+++ b/core/java/com/android/internal/os/CameraPowerCalculator.java
@@ -42,7 +42,7 @@
mPowerEstimator.calculateDuration(u.getCameraTurnedOnTimer(), rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED);
final double powerMah = mPowerEstimator.calculatePower(durationMs);
- app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CAMERA, durationMs)
+ app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah);
}
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index 4aafec5..2a55aa9 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -97,9 +97,7 @@
result);
app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, result.powerMah, powerModel)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU, result.durationMs)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND,
- result.durationFgMs)
+ .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CPU, result.durationMs)
.setPackageWithHighestDrain(result.packageWithHighestDrain);
}
diff --git a/core/java/com/android/internal/os/FlashlightPowerCalculator.java b/core/java/com/android/internal/os/FlashlightPowerCalculator.java
index 6c29a91..cbe0cde 100644
--- a/core/java/com/android/internal/os/FlashlightPowerCalculator.java
+++ b/core/java/com/android/internal/os/FlashlightPowerCalculator.java
@@ -39,7 +39,7 @@
final long durationMs = mPowerEstimator.calculateDuration(u.getFlashlightTurnedOnTimer(),
rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
final double powerMah = mPowerEstimator.calculatePower(durationMs);
- app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_FLASHLIGHT, durationMs)
+ app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, powerMah);
}
diff --git a/core/java/com/android/internal/os/GnssPowerCalculator.java b/core/java/com/android/internal/os/GnssPowerCalculator.java
index 0e0870d..7eb4b4a 100644
--- a/core/java/com/android/internal/os/GnssPowerCalculator.java
+++ b/core/java/com/android/internal/os/GnssPowerCalculator.java
@@ -74,7 +74,7 @@
powerMah = computePower(durationMs, averageGnssPowerMa);
}
- app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_GNSS, durationMs)
+ app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_GNSS, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS, powerMah, powerModel);
}
diff --git a/core/java/com/android/internal/os/IdlePowerCalculator.java b/core/java/com/android/internal/os/IdlePowerCalculator.java
index 5cb54bd..0c80deb 100644
--- a/core/java/com/android/internal/os/IdlePowerCalculator.java
+++ b/core/java/com/android/internal/os/IdlePowerCalculator.java
@@ -55,7 +55,7 @@
if (mPowerMah != 0) {
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_IDLE)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_IDLE, mPowerMah)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_IDLE, mDurationMs);
+ .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_IDLE, mDurationMs);
}
}
diff --git a/core/java/com/android/internal/os/MemoryPowerCalculator.java b/core/java/com/android/internal/os/MemoryPowerCalculator.java
index 9ec40c6..5d5c155 100644
--- a/core/java/com/android/internal/os/MemoryPowerCalculator.java
+++ b/core/java/com/android/internal/os/MemoryPowerCalculator.java
@@ -32,7 +32,7 @@
final double powerMah = calculatePower(batteryStats, rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED);
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_MEMORY)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MEMORY, durationMs)
+ .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_MEMORY, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_MEMORY, powerMah);
}
diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
index d441d45..4db15a4 100644
--- a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
+++ b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
@@ -107,7 +107,7 @@
if (total.remainingPowerMah != 0 || total.totalAppPowerMah != 0) {
builder.getOrCreateSystemBatteryConsumerBuilder(
SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MOBILE_RADIO,
+ .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
total.durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
total.remainingPowerMah + total.totalAppPowerMah,
@@ -128,7 +128,7 @@
radioActiveDurationMs, consumptionUC);
total.totalAppPowerMah += powerMah;
- app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MOBILE_RADIO,
+ app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
radioActiveDurationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, powerMah,
powerModel);
diff --git a/core/java/com/android/internal/os/PhonePowerCalculator.java b/core/java/com/android/internal/os/PhonePowerCalculator.java
index 6f279d99..2e3bff3 100644
--- a/core/java/com/android/internal/os/PhonePowerCalculator.java
+++ b/core/java/com/android/internal/os/PhonePowerCalculator.java
@@ -46,7 +46,7 @@
if (phoneOnPower != 0) {
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_PHONE)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_PHONE, phoneOnTimeMs);
+ .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs);
}
}
diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java
index 0743c89..dc0f719 100644
--- a/core/java/com/android/internal/os/ScreenPowerCalculator.java
+++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java
@@ -81,7 +81,7 @@
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
calculateAppUsingMeasuredEnergy(appPowerAndDuration, app.getBatteryStatsUid(),
rawRealtimeUs);
- app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN,
+ app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN,
appPowerAndDuration.durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN,
appPowerAndDuration.powerMah, powerModel);
@@ -96,7 +96,7 @@
}
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_SCREEN)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN,
+ .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN,
totalPowerAndDuration.durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN,
Math.max(totalPowerAndDuration.powerMah, totalAppPower), powerModel)
@@ -251,7 +251,7 @@
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
final long durationMs = activityTimeArray.get(app.getUid(), 0);
final double powerMah = totalScreenPowerMah * durationMs / totalActivityTimeMs;
- app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN, durationMs)
+ app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN, powerMah,
BatteryConsumer.POWER_MODEL_POWER_PROFILE);
}
diff --git a/core/java/com/android/internal/os/SensorPowerCalculator.java b/core/java/com/android/internal/os/SensorPowerCalculator.java
index 78c4fe2..d18b7b1 100644
--- a/core/java/com/android/internal/os/SensorPowerCalculator.java
+++ b/core/java/com/android/internal/os/SensorPowerCalculator.java
@@ -40,7 +40,7 @@
@Override
protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
- app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SENSORS,
+ app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SENSORS,
calculateDuration(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED))
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SENSORS,
calculatePowerMah(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED));
diff --git a/core/java/com/android/internal/os/VideoPowerCalculator.java b/core/java/com/android/internal/os/VideoPowerCalculator.java
index 5d6caf5..0cad9a7 100644
--- a/core/java/com/android/internal/os/VideoPowerCalculator.java
+++ b/core/java/com/android/internal/os/VideoPowerCalculator.java
@@ -39,7 +39,7 @@
final long durationMs = mPowerEstimator.calculateDuration(u.getVideoTurnedOnTimer(),
rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
final double powerMah = mPowerEstimator.calculatePower(durationMs);
- app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO, durationMs)
+ app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO, powerMah);
}
}
diff --git a/core/java/com/android/internal/os/WakelockPowerCalculator.java b/core/java/com/android/internal/os/WakelockPowerCalculator.java
index 0f4767b..194b6b8 100644
--- a/core/java/com/android/internal/os/WakelockPowerCalculator.java
+++ b/core/java/com/android/internal/os/WakelockPowerCalculator.java
@@ -57,7 +57,7 @@
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
calculateApp(result, app.getBatteryStatsUid(), rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED);
- app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK, result.durationMs)
+ app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.powerMah);
totalAppDurationMs += result.durationMs;
@@ -74,7 +74,7 @@
if (osBatteryConsumer != null) {
calculateRemaining(result, batteryStats, rawRealtimeUs, rawUptimeUs,
BatteryStats.STATS_SINCE_CHARGED, osPowerMah, osDurationMs, totalAppDurationMs);
- osBatteryConsumer.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK,
+ osBatteryConsumer.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK,
result.durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.powerMah);
}
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index 11219ec..ef5b147 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -100,7 +100,7 @@
totalAppDurationMs += powerDurationAndTraffic.durationMs;
totalAppPowerMah += powerDurationAndTraffic.powerMah;
- app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI,
+ app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI,
powerDurationAndTraffic.durationMs);
app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI,
powerDurationAndTraffic.powerMah, powerModel);
@@ -118,7 +118,7 @@
totalAppDurationMs, totalAppPowerMah, consumptionUC);
systemBatteryConsumerBuilder
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI,
+ .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI,
powerDurationAndTraffic.durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI,
totalAppPowerMah + powerDurationAndTraffic.powerMah, powerModel)
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index 49dbbaa..a61e86b 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -30,4 +30,5 @@
void reportFullscreenMode(boolean fullscreen);
void updateActivityViewToScreenMatrix(int bindSequence, in float[] matrixValues);
void setImeTraceEnabled(boolean enabled);
+ void throwExceptionFromSystem(String message);
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 93cd4e9..3b8f440 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -52,9 +52,9 @@
oneway void getLastInputMethodSubtype(in IInputMethodSubtypeResultCallback resultCallback);
oneway void showSoftInput(in IInputMethodClient client, IBinder windowToken, int flags,
- in ResultReceiver resultReceiver, in IBooleanResultCallback resultCallback);
+ in ResultReceiver resultReceiver, int reason, in IBooleanResultCallback resultCallback);
oneway void hideSoftInput(in IInputMethodClient client, IBinder windowToken, int flags,
- in ResultReceiver resultReceiver, in IBooleanResultCallback resultCallback);
+ in ResultReceiver resultReceiver, int reason, in IBooleanResultCallback resultCallback);
// If windowToken is null, this just does startInput(). Otherwise this reports that a window
// has gained focus, and if 'attribute' is non-null then also does startInput.
// @NonNull
@@ -68,6 +68,12 @@
int unverifiedTargetSdkVersion,
in IInputBindResultResultCallback inputBindResult);
+ oneway void reportWindowGainedFocusAsync(
+ boolean nextFocusHasConnection, in IInputMethodClient client, in IBinder windowToken,
+ /* @StartInputFlags */ int startInputFlags,
+ /* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
+ int windowFlags, int unverifiedTargetSdkVersion);
+
oneway void showInputMethodPickerFromClient(in IInputMethodClient client,
int auxiliarySubtypeMode, in IVoidResultCallback resultCallback);
oneway void showInputMethodPickerFromSystem(in IInputMethodClient client,
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
index c6afd78..acb4754 100644
--- a/core/java/com/android/internal/view/IInputMethodSession.aidl
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -43,8 +43,6 @@
void appPrivateCommand(String action, in Bundle data);
- void toggleSoftInput(int showFlags, int hideFlags);
-
void finishSession();
void updateCursorAnchorInfo(in CursorAnchorInfo cursorAnchorInfo);
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index bab4e93b..4e96ae7 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -128,6 +128,8 @@
private CharSequence mFallbackChatName;
private CharSequence mFallbackGroupChatName;
private CharSequence mConversationTitle;
+ private int mMessageSpacingStandard;
+ private int mMessageSpacingGroup;
private int mNotificationHeaderExpandedPadding;
private View mConversationHeader;
private View mContentContainer;
@@ -241,6 +243,10 @@
mContentContainer = findViewById(R.id.notification_action_list_margin_target);
mExpandButtonAndContentContainer = findViewById(R.id.expand_button_and_content_container);
mExpandButton = findViewById(R.id.expand_button);
+ mMessageSpacingStandard = getResources().getDimensionPixelSize(
+ R.dimen.notification_messaging_spacing);
+ mMessageSpacingGroup = getResources().getDimensionPixelSize(
+ R.dimen.notification_messaging_spacing_conversation_group);
mNotificationHeaderExpandedPadding = getResources().getDimensionPixelSize(
R.dimen.conversation_header_expanded_padding_end);
mContentMarginEnd = getResources().getDimensionPixelSize(
@@ -699,6 +705,10 @@
}
private void updatePaddingsBasedOnContentAvailability() {
+ // groups have avatars that need more spacing
+ mMessagingLinearLayout.setSpacing(
+ mIsOneToOne ? mMessageSpacingStandard : mMessageSpacingGroup);
+
int messagingPadding = mIsOneToOne || mIsCollapsed
? 0
// Add some extra padding to the messages, since otherwise it will overlap with the
@@ -1082,15 +1092,18 @@
private void updateExpandButton() {
int buttonGravity;
- int containerHeight;
ViewGroup newContainer;
if (mIsCollapsed) {
buttonGravity = Gravity.CENTER;
- containerHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
+ // NOTE(b/182474419): In order for the touch target of the expand button to be the full
+ // height of the notification, we would want the mExpandButtonContainer's height to be
+ // set to WRAP_CONTENT (or 88dp) when in the collapsed state. Unfortunately, that
+ // causes an unstable remeasuring infinite loop when the unread count is visible,
+ // causing the layout to occasionally hide the messages. As an aside, that naive
+ // solution also causes an undesirably large gap between content and smart replies.
newContainer = mExpandButtonAndContentContainer;
} else {
buttonGravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
- containerHeight = ViewGroup.LayoutParams.MATCH_PARENT;
newContainer = this;
}
mExpandButton.setExpanded(!mIsCollapsed);
@@ -1099,7 +1112,6 @@
// content when collapsed, but allows the content to flow under it when expanded.
if (newContainer != mExpandButtonContainer.getParent()) {
((ViewGroup) mExpandButtonContainer.getParent()).removeView(mExpandButtonContainer);
- mExpandButtonContainer.getLayoutParams().height = containerHeight;
newContainer.addView(mExpandButtonContainer);
}
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index 7cfd46c..cb1d387 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -17,6 +17,7 @@
package com.android.internal.widget;
import android.annotation.Nullable;
+import android.annotation.Px;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -251,6 +252,16 @@
return super.drawChild(canvas, child, drawingTime);
}
+ /**
+ * Set the spacing to be applied between views.
+ */
+ public void setSpacing(@Px int spacing) {
+ if (mSpacing != spacing) {
+ mSpacing = spacing;
+ requestLayout();
+ }
+ }
+
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(mContext, attrs);
diff --git a/core/proto/android/providers/OWNERS b/core/proto/android/providers/OWNERS
new file mode 100644
index 0000000..1f5cd9a
--- /dev/null
+++ b/core/proto/android/providers/OWNERS
@@ -0,0 +1 @@
+include /packages/SettingsProvider/OWNERS
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 8ee0e39..c3d1596 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -285,6 +285,7 @@
// Deprecated, use enable_non_resizable_multi_window
optional SettingProto enable_sizecompat_freeform = 7 [ (android.privacy).dest = DEST_AUTOMATIC, deprecated = true ];
optional SettingProto enable_non_resizable_multi_window = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto disable_window_blurs = 9 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Development development = 39;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e4f16a9..4dc4bef 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2333,6 +2333,11 @@
<permission android:name="android.permission.CAMERA_SEND_SYSTEM_EVENTS"
android:protectionLevel="signature|privileged" />
+ <!-- Allows injecting the external camera to replace the internal camera.
+ @hide -->
+ <permission android:name="android.permission.CAMERA_INJECT_EXTERNAL_CAMERA"
+ android:protectionLevel="signature" />
+
<!-- =========================================== -->
<!-- Permissions associated with telephony state -->
<!-- =========================================== -->
@@ -2709,10 +2714,9 @@
<permission android:name="android.permission.CREATE_USERS"
android:protectionLevel="signature" />
- <!-- @SystemApi @hide Allows an application to access data blobs across users.
- This permission is not available to third party applications. -->
+ <!-- Allows an application to access data blobs across users. -->
<permission android:name="android.permission.ACCESS_BLOBS_ACROSS_USERS"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development|role" />
<!-- @hide Allows an application to set the profile owners and the device owner.
This permission is not available to third party applications.-->
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 445bac5..210c5bc 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1622,7 +1622,7 @@
<string name="media_route_button_content_description" msgid="2299223698196869956">"Saai uit"</string>
<string name="media_route_chooser_title" msgid="6646594924991269208">"Koppel aan toestel"</string>
<string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Saai skerm uit na toestel"</string>
- <string name="media_route_chooser_searching" msgid="6119673534251329535">"Soek tans vir toestelle…"</string>
+ <string name="media_route_chooser_searching" msgid="6119673534251329535">"Soek tans vir toestelle …"</string>
<string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Instellings"</string>
<string name="media_route_controller_disconnect" msgid="7362617572732576959">"Ontkoppel"</string>
<string name="media_route_status_scanning" msgid="8045156315309594482">"Skandeer tans..."</string>
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarg"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Onbekende portret"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Onbekende landskap"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Gekanselleer"</string>
@@ -1852,9 +1864,9 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Opgedateer deur jou administrateur"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Uitgevee deur jou administrateur"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Batterybespaarder skakel Donkertema aan en beperk of skakel agtergrondaktiwiteit, sommige visuele effekte en ander kenmerke, soos \"Ok Google\", af\n\n"<annotation id="url">"Kom meer te wete"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Batterybespaarder skakel Donkertema aan en beperk of skakel agtergrondaktiwiteit, sommige visuele effekte en ander kenmerke, soos \"Ok Google\", af."</string>
- <string name="data_saver_description" msgid="4995164271550590517">"Databespaarder verhoed sommige programme om data in die agtergrond te stuur of te aanvaar om datagebruik te help verminder. \'n Program wat jy tans gebruik kan by data ingaan, maar sal dit dalk minder gereeld doen. Dit kan byvoorbeeld beteken dat prente nie wys totdat jy op hulle tik nie."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Batterybespaarder skakel Donkertema aan en beperk of skakel agtergrondaktiwiteit, sommige visuele effekte en sekere kenmerke af.\n\n"<annotation id="url">"Kom meer te wete"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Batterybespaarder skakel Donkertema aan en beperk of skakel agtergrondaktiwiteit, sommige visuele effekte en sekere kenmerke af."</string>
+ <string name="data_saver_description" msgid="4995164271550590517">"Databespaarder verhoed sommige programme om data in die agtergrond te stuur of te aanvaar om datagebruik te help verminder. \'n Program wat jy tans gebruik kan by data ingaan, maar sal dit dalk minder gereeld doen. Dit kan byvoorbeeld beteken dat prente nie wys voordat jy op hulle tik nie."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Skakel Databespaarder aan?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Skakel aan"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Hierdie kennisgewing is gedegradeer na Stil. Tik om terugvoer te gee."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Hierdie kennisgewing is hoër gegradeer. Tik om terugvoer te gee."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Hierdie kennisgewing is laer gegradeer. Tik om terugvoer te gee."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Probeer verbeterde kennisgewings"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Skakel verbeterde kennisgewings aan sodat jy aanhou om voorgestelde handelinge, antwoorde en meer te ontvang. Android se aanpasbare kennisgewings word nie meer gesteun nie."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Skakel aan"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Nie nou nie"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Verbeterde kennisgewings"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Voorgestelde handelinge en antwoorde word nou deur verbeterde kennisgewings verskaf. Android se aanpasbare kennisgewings word nie meer gesteun nie."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Skakel af"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Kom meer te wete"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Verbeterde kennisgewings kan alle kennisgewinginhoud lees, insluitend persoonlike inligting soos kontakname en boodskappe. Hierdie kenmerk kan ook kennisgewings toemaak of handelingknoppies in kennisgewings gebruik, soos om foonoproepe te beantwoord.\n\nHierdie kenmerk kan ook Prioriteitmodus aan- of afskakel en soortgelyke instellings verander."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Verbeterde kennisgewings het Android se aanpasbare kennisgewings in Android 12 vervang. Hierdie kenmerk wys voorgestelde handelinge en antwoorde, en organiseer jou kennisgewings.\n\nVerbeterde kennisgewings het toegang tot kennisgewinginhoud, insluitend persoonlike inligting soos kontakname en -boodskappe. Hierdie kenmerk kan ook kennisgewings toemaak of daarop antwoord, soos om foonoproepe te beantwoord en Moenie Steur Nie te beheer."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Roetinemodus-inligtingkennisgewing"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery kan afloop voordat dit normaalweg gelaai word"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterybespaarder is geaktiveer om batterylewe te verleng"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index ee286bd..d5d06633 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"ሞናርክ"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"ኳርቶ"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"ፉልስካፕ"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"አር ኦ ሲ 8ኬ"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"አር ኦ ሲ 16ኬ"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"ፒ አር ሲ 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"ካሁ"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"ካኩ2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"ዩ4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"የማይታወቅ የቁም"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"የማይታወቅ የወርድ"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ተትቷል"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"በእርስዎ አስተዳዳሪ ተዘምኗል"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"በእርስዎ አስተዳዳሪ ተሰርዟል"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"እሺ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"የባትሪ ኃይል ቆጣቢ የጠቆር ያለ ገጽታን ያበራል እና የጀርባ እንቅስቃሴን፣ አንዳንድ የእይታ ውጤቶችን እና እንደ «Hey Google» ያሉ ባህሪያትን ይገድባል ወይም ያጠፋል።\n\n"<annotation id="url">"የበለጠ ለመረዳት"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"የባትሪ ኃይል ቆጣቢ የጠቆር ያለ ገጽታን ያበራል እና የጀርባ እንቅስቃሴን፣ አንዳንድ የእይታ ውጤቶችን እና እንደ «Hey Google» ያሉ ባህሪያትን ይገድባል ወይም ያጠፋል።"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"የባትሪ ኃይል ቆጣቢ ጠቆር ያለ ገጽታን ያበራል እና የጀርባ እንቅስቃሴን፣ አንዳንድ ምስላዊ ተጽዕኖዎችን እና የተወሰኑ ባህሪያትን ይገድባል ወይም ያጠፋል።\n\n"<annotation id="url">"የበለጠ ለመረዳት"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"የባትሪ ኃይል ቆጣቢ ጠቆር ያለ ገጽታን ያበራል እና የጀርባ እንቅስቃሴን፣ አንዳንድ ምስላዊ ተጽዕኖዎችን እና የተወሰኑ ባህሪያትን ይገድባል ወይም ያጠፋል።"</string>
<string name="data_saver_description" msgid="4995164271550590517">"የውሂብ አጠቃቀም እንዲቀንስ ለማገዝ ውሂብ ቆጣቢ አንዳንድ መተግበሪያዎች ከበስተጀርባ ሆነው ውሂብ እንዳይልኩ ወይም እንዳይቀበሉ ይከለክላቸዋል። በአሁኑ ጊዜ እየተጠቀሙበት ያለ መተግበሪያ ውሂብ ሊደርስ ይችላል፣ ነገር ግን ባነሰ ተደጋጋሚነት ሊሆን ይችላል። ይሄ ማለት ለምሳሌ ምስሎችን መታ እስኪያደርጓቸው ድረስ ላይታዩ ይችላሉ ማለት ነው።"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ውሂብ ቆጣቢ ይጥፋ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"አብራ"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ይህ ማሳወቂያ ወደ ዝምታ ዝቅ ብሏል። ግብረመልስ ለመስጠት መታ ያድርጉ።"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ይህ ማሳወቂያ ከፍተኛ ደረጃ ተሰጥቶታል። ግብረመልስ ለመስጠት መታ ያድርጉ።"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ይህ ማሳወቂያ ዝቅተኛ ደረጃ ተሰጥቶታል። ግብረመልስ ለመስጠት መታ ያድርጉ።"</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"የተሻሻሉ ማሳወቂያዎችን ይሞክሩ"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"የተጠቆሙ እርምጃዎችን፣ ምላሾችን እና ሌሎችን ማግኘትን ለመቀጠል የተሻሻሉ ማሳወቂያዎችን ያብሩ። የAndroid አስማሚ ማሳወቂያዎች ከአሁን በኋላ አይደገፉም።"</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"አብራ"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"አሁን አይደለም"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"የበለጠ ለመረዳት"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"የተሻሻሉ ማሳወቂያዎች እንደ የእውቂያ ስሞች እና መልዕክቶች ያሉ የግል መረጃዎችን ጨምሮ ሁሉንም የማሳወቂያ ይዘቶችን ማንበብ ይችላሉ። ይህ ባህሪ ማሳወቂያዎችን ማሰናከል ወይም እንደ የስልክ ጥሪዎችን ማንሳት በመሳሰሉ ማሳወቂያዎች ውስጥ ባሉ አዝራሮች ላይ እርምጃዎችንም አዝራሮች ላይ እርምጃዎችንም መውሰድ ይችላል።\n\nይህ ባህሪ የቅድሚያ ሁነታን ማብራት ወይም ማጥፋት እና ተዛማጅ ቅንብሮችን መለወጥ ይችላል።"</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"የዕለት ተዕለት ሁነታ መረጃ ማሳወቂያዎች"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ባትሪ ከተለመደው ኃይል መሙላት በፊት ሊያልቅ ይችላል"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"የባትሪ ቆጣቢ የባትሪ ዕድሜን ለማራዘም ገብሯል።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index ad295cb..1b7e8fd 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1861,6 +1861,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"فولسكاب"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1897,6 +1908,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"عمودي غير معروف"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"أفقي غير معروف"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ملغاة"</string>
@@ -1944,8 +1956,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"تم التحديث بواسطة المشرف"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"تم الحذف بواسطة المشرف"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"حسنًا"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"يؤدي استخدام خيار \"توفير شحن البطارية\" إلى تفعيل \"المظهر الداكن\" وتقييد أو إيقاف النشاط في الخلفية وبعض التأثيرات المرئية والميزات الأخرى، مثلاً \"Ok Google\".\n\n"<annotation id="url">"مزيد من المعلومات"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"يؤدي استخدام خيار \"توفير شحن البطارية\" إلى تفعيل \"المظهر الداكن\" وتقييد أو إيقاف النشاط في الخلفية وبعض التأثيرات المرئية والميزات الأخرى، مثلاً \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"يؤدي استخدام خيار \"توفير شحن البطارية\" إلى تفعيل \"المظهر الداكن\" وتقييد أو إيقاف الأنشطة في الخلفية وبعض التأثيرات المرئية وميزات معيّنة.\n\n"<annotation id="url">"مزيد من المعلومات"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"يؤدي استخدام خيار \"توفير شحن البطارية\" إلى تفعيل \"المظهر الداكن\" وتقييد أو إيقاف الأنشطة في الخلفية وبعض التأثيرات المرئية وميزات معيّنة."</string>
<string name="data_saver_description" msgid="4995164271550590517">"للمساعدة في خفض استخدام البيانات، تمنع ميزة \"توفير البيانات\" بعض التطبيقات من إرسال البيانات وتلقّيها في الخلفية. يمكن للتطبيقات المتاحة لديك الآن استخدام البيانات، ولكن لا يمكنها الإكثار من ذلك. وهذا يعني أن الصور مثلاً لا تظهر حتى تنقر عليها."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"هل تريد تفعيل توفير البيانات؟"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"تفعيل"</string>
@@ -2205,12 +2217,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"تم خفض ترتيب هذا الإشعار إلى الوضع \"صامت\". انقر لإرسال ملاحظات وآراء."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"تمت زيادة ترتيب هذا الإشعار. انقر لإرسال ملاحظات وآراء."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"تم خفض ترتيب هذا الإشعار. انقر لإرسال ملاحظات وآراء."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"تجربة الإشعارات المحسّنة"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"لمواصلة الحصول على الردود والإجراءات المقترحة والمزيد، عليك تفعيل الإشعارات المحسّنة. لم تعد الإشعارات التكيُّفية لنظام التشغيل Android متاحة."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"تفعيل"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"لاحقًا"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"مزيد من المعلومات"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"يمكن للإشعارات المحسّنة قراءة كل محتوى الإشعارات، بما في ذلك المعلومات الشخصية، مثلاً أسماء جهات الاتصال والرسائل. يمكن لهذه الميزة أيضًا إغلاق الإشعارات أو اتخاذ إجراءات من خلال الأزرار في الإشعارات، مثلاً الردّ على مكالمات الهاتف.\n\nويمكن لهذه الميزة أيضًا تفعيل وضع \"الأولوية\" أو إيقافه وتغيير الإعدادات ذات الصلة."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"إشعار معلومات \"وضع سلسلة الإجراءات\""</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"قد تنفد طاقة البطارية قبل الشحن المعتاد"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"تم تفعيل \"توفير شحن البطارية\" لإطالة عمرها."</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 5eac3d0..350e981 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1708,7 +1708,7 @@
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"শ্বৰ্টকাট অফ কৰক"</string>
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"শ্বৰ্টকাট ব্যৱহাৰ কৰক"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ৰং বিপৰীতকৰণ"</string>
- <string name="color_correction_feature_name" msgid="3655077237805422597">"ৰং শুধৰণী"</string>
+ <string name="color_correction_feature_name" msgid="3655077237805422597">"ৰং শুধৰণি"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"এক্সট্ৰা ডিম"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ভলিউম কীসমূহ ধৰি ৰাখক। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অন কৰা হ\'ল।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ভলিউম কী ধৰি ৰাখিছিল। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অফ কৰা হ\'ল।"</string>
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"ম\'নাৰ্ক"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"কুৱাট্ৰো"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"ফুলস্কেপ"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,8 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <!-- no translation found for mediasize_japanese_l (1326765321473431817) -->
+ <skip />
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"অজ্ঞাত প\'ৰ্ট্ৰেইট"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"অজ্ঞাত লেণ্ডস্কেইপ"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"বাতিল কৰা হ’ল"</string>
@@ -1852,9 +1865,11 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"আপোনাৰ প্ৰশাসকে আপেডট কৰিছে"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"আপোনাৰ প্ৰশাসকে মচিছে"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"বেটাৰী সঞ্চয়কাৰীয়ে গাঢ় থীম অন কৰে আৰু নেপথ্যৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল ইফেক্ট আৰু “Hey Google”ৰ দৰে সুবিধাসমূহ অফ কৰে অথবা সীমাবদ্ধ কৰে\n\n"<annotation id="url">"অধিক জানক"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"বেটাৰী সঞ্চয়কাৰীয়ে গাঢ় থীম অন কৰে আৰু নেপথ্যৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল ইফেক্ট আৰু “Hey Google”ৰ দৰে সুবিধাসমূহ অফ কৰে অথবা সীমাবদ্ধ কৰে।"</string>
- <string name="data_saver_description" msgid="4995164271550590517">"ডেটা ব্য়ৱহাৰ মাত্ৰা কম কৰিবৰ বাবে ডেটা সঞ্চয়কাৰীয়ে কিছুমান এপক নেপথ্য়ত ডেটা প্ৰেৰণ বা সংগ্ৰহ কৰাত বাধা প্ৰদান কৰে। আপুনি বৰ্তমান ব্য়ৱহাৰ কৰি থকা এটা এপে ডেটা ব্য়ৱহাৰ কৰিব পাৰে, কিন্তু সঘনাই এই কার্য কৰিব নোৱাৰিব পাৰে। ইয়াৰ অৰ্থ এইয়ে হ\'ব পাৰে যে, উদাহৰণস্বৰূপে, আপুনি নিটিপা পর্যন্ত প্ৰতিচ্ছবিসমূহ দেখুওৱা নহ’ব।"</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (5693741424234005958) -->
+ <skip />
+ <string name="data_saver_description" msgid="4995164271550590517">"ডেটা ব্য়ৱহাৰৰ হ্ৰাস কৰিবলৈ ডেটা সঞ্চয়কাৰীয়ে কিছুমান এপক নেপথ্য়ত ডেটা প্ৰেৰণ বা সংগ্ৰহ কৰাত বাধা প্ৰদান কৰে। আপুনি বৰ্তমান ব্য়ৱহাৰ কৰি থকা এটা এপে ডেটা এক্সেছ কৰিব পাৰে, কিন্তু সঘনাই এক্সেছ কৰিব নোৱাৰিব পাৰে। ইয়াৰ অৰ্থ উদাহৰণস্বৰূপে এয়া হ\'ব পাৰে যে, আপুনি নিটিপা পর্যন্ত প্ৰতিচ্ছবিসমূহ দেখুওৱা নহ’ব।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ডেটা সঞ্চয়কাৰী অন কৰিবনে?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"অন কৰক"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
@@ -1929,8 +1944,7 @@
<string name="close_button_text" msgid="10603510034455258">"বন্ধ কৰক"</string>
<string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
<string name="call_notification_answer_action" msgid="5999246836247132937">"উত্তৰ দিয়ক"</string>
- <!-- no translation found for call_notification_answer_video_action (2086030940195382249) -->
- <skip />
+ <string name="call_notification_answer_video_action" msgid="2086030940195382249">"ভিডিঅ’"</string>
<string name="call_notification_decline_action" msgid="3700345945214000726">"প্ৰত্যাখ্যান কৰক"</string>
<string name="call_notification_hang_up_action" msgid="9130720590159188131">"কল কাটি দিয়ক"</string>
<string name="call_notification_incoming_text" msgid="6143109825406638201">"অন্তৰ্গামী কল"</string>
@@ -2074,12 +2088,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"এই জাননীটোৰ গুৰুত্ব নীৰৱলৈ হ্ৰাস কৰা হৈছে। মতামত দিবলৈ টিপক।"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"এই জাননীটোৰ স্থান ওপৰলৈ কৰা হৈছে। মতামত দিবলৈ টিপক।"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"এই জাননীটোৰ স্থান তললৈ কৰা হৈছে। মতামত দিবলৈ টিপক।"</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"উন্নত জাননী ব্যৱহাৰ কৰি চাওক"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"পৰামৰ্শ দিয়া কাৰ্য, প্ৰত্যুত্তৰ আৰু বহুতো সুবিধা পাই থাকিবলৈ উন্নত জাননী অন কৰক। Androidৰ অভিযোজিত জাননী আৰু সমৰ্থিত নহয়।"</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"অন কৰক"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"এতিয়া নহয়"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"অধিক জানক"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"উন্নত প্ৰত্যুত্তৰে সম্পৰ্কৰ নাম আৰু বাৰ্তাৰ দৰে ব্যক্তিগত তথ্যৰ লগতে আটাইবোৰ জাননীৰ সমল পঢ়িব পাৰে। এই সুবিধাটোৱে জাননী অগ্ৰাহ্য কৰাৰ লগতে জাননীত থকা ফ’ন কলৰ উত্তৰ দিয়াৰ দৰে কাৰ্য বুটামৰ ওপৰত কাৰ্যব্যৱস্থা ল’ব পাৰে।\n\nলগতে, এই সুবিধাটোৱে অগ্ৰাধিকাৰ দিয়া ম’ড অন অথবা অফ কৰিব পাৰে আৰু সম্পৰ্কিত ছেটিং সলনি কৰিব পাৰে।"</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ৰুটিন ম’ডৰ তথ্য জাননী"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"চ্চাৰ্জ কৰাৰ সচৰাচৰ সময়ৰ আগতেই বেটাৰি শেষ হ’ব পাৰে"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"বেটাৰিৰ খৰচ কমাবলৈ বেটাৰি সঞ্চয়কাৰী অন কৰা হৈছে"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 0a1c880..1bdc646 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Naməlum portret"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Naməlum mənzərə"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Ləğv edildi"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Admin tərəfindən yeniləndi"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Admin tərəfindən silindi"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Enerjiyə Qənaət funksiyası Qaranlıq temanı aktiv edir və arxa fondakı fəaliyyəti, bəzi vizual effektləri və “Hey Google” kimi digər funksiyaları məhdudlaşdırır və ya deaktiv edir\n\n"<annotation id="url">"Ətraflı məlumat"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Enerjiyə Qənaət funksiyası Qaranlıq temanı aktiv edir və arxa fondakı fəaliyyəti, bəzi vizual effektləri və “Hey Google” kimi digər funksiyaları məhdudlaşdırır və ya deaktiv edir."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Enerjiyə Qənaət Qaranlıq temanı aktiv edir, arxa fondakı fəaliyyətlər, bəzi vizual effektlər və müəyyən funksiyaları məhdudlaşdırır və ya deaktiv edir.\n\n"<annotation id="url">"Ətraflı məlumat"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Enerjiyə Qənaət Qaranlıq temanı aktiv edir, arxa fondakı fəaliyyətlər, bəzi vizual effektlər və müəyyən funksiyaları məhdudlaşdırır və ya deaktiv edir."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Mobil interneti qənaətlə işlətmək məqsədilə Data Qanaəti bəzi tətbiqlərin fonda data göndərməsinin və qəbulunun qarşısını alır. Hazırda işlətdiyiniz tətbiq nisbətən az müntəzəmliklə data istifadə edə bilər. Örnək olaraq bu, o deməkdir ki, şəkil fayllarına toxunmadıqca onlar açılmayacaq."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Trafikə qənaət edilsin?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivləşdirin"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Bu bildiriş Səssiz rejimə keçirilib. Rəy bildirmək üçün toxunun."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Bu bildiriş yuxarı sıraya keçirilib. Rəy bildirmək üçün toxunun."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Bu bildiriş aşağı sıraya keçirilib. Rəy bildirmək üçün toxunun."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Genişləndirilmiş bildirişləri sınayın"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Təklif olunan əməliyyatlar, cavablar və daha çoxunu almağa davam etmək üçün genişləndirilmiş bildirişləri aktiv edin. Android Adaptiv Bildirişləri artıq dəstəklənmir."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aktiv edin"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"İndi yox"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Ətraflı məlumat"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Genişləndirilmiş bildirişlər, kontakt adları və mesajlar kimi şəxsi məlumatlar daxil olmaqla bütün bildiriş məzmununu oxuya bilər. Bu funksiya həmçinin bildirişləri qapada və ya telefon zənglərinə cavab vermək kimi bildirişlərdəki düymələr üzərində əməliyyatlar edə bilər.\n\nBu funksiya həmçinin Prioritet rejimini aktiv və ya deaktiv edə və əlaqəli ayarları dəyişdirə bilər."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rejim üçün məlumat bildirişi"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batareya həmişəki vaxtdan əvvəl bitə bilər"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Enerjiyə Qənaət rejimi batareya istifadəsinin müddətini artırmaq üçün aktiv edilir"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 5a7e890..450470e 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1795,6 +1795,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1831,6 +1842,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Nepoznata veličina, uspravno"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Nepoznata veličina, vodoravno"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Otkazano je"</string>
@@ -1875,8 +1887,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Potvrdi"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizuelne efekte i funkcije, na primer, „Hej Google“.\n\n"<annotation id="url">"Saznajte više"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizuelne efekte i funkcije, na primer, „Hej Google“."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizuelne efekte i određene funkcije.\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizuelne efekte i određene funkcije."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Da bi se smanjila potrošnja podataka, Ušteda podataka sprečava neke aplikacije da šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može da pristupa podacima, ali će to činiti ređe. Na primer, slike se neće prikazivati dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Želite da uključite Uštedu podataka?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Uključi"</string>
@@ -2106,12 +2118,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Ovo obaveštenje je degradirano u Nečujno. Dodirnite da biste naveli povratne informacije."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Ovo obaveštenje je rangirano više. Dodirnite da biste naveli povratne informacije."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Ovo obaveštenje je rangirano niže. Dodirnite da biste naveli povratne informacije."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Probajte poboljšana obaveštenja"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Uključite poboljšana obaveštenja da biste i dalje dobijali preporučene radnje, odgovore i drugo. Prilagodljiva obaveštenja za Android više nisu podržana."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Uključi"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ne sada"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Poboljšana obaveštenja"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Predložene radnje i odgovore sada dobijate pomoću poboljšanih obaveštenja. Prilagodljiva obaveštenja za Android više nisu podržana."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Potvrdi"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Isključi"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saznajte više"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Poboljšana obaveštenja mogu da čitaju sadržaj svih obaveštenja, uključujući lične podatke, poput imena kontakata i poruka. Ova funkcija može i da odbacuje obaveštenja ili aktivira dugmad u obaveštenjima, poput javljanja na telefonske pozive.\n\nOva funkcija može i da uključi ili isključi Prioritetni režim i da menja povezana podešavanja."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Poboljšana obaveštenja su zamenila Android prilagodljiva obaveštenja u Android-u 12. Ova funkcija pokazuje predložene radnje i odgovore i organizuje obaveštenja.\n\nPoboljšana obaveštenja mogu da pristupaju sadržaju obaveštenja, uključujući lične informacije poput imena kontakata i poruka. Ova funkcija može i da odbacuje obaveštenja ili da odgovara na njih, na primer, da se javlja na telefonske pozive i kontroliše režim Ne uznemiravaj."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Obaveštenje o informacijama Rutinskog režima"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterija će se možda isprazniti pre uobičajenog punjenja"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Ušteda baterije je aktivirana da bi se produžilo trajanje baterije"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index c0915d2c..f117799 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1817,6 +1817,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1853,6 +1864,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Невядомы (кніжная арыентацыя)"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Невядомы (альбомная арыентацыя)"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Скасавана"</string>
@@ -1898,8 +1910,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Абноўлены вашым адміністратарам"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Выдалены вашым адміністратарам"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"У рэжыме эканоміі зараду ўключаецца цёмная тэма і абмяжоўваюцца ці выключаюцца дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і функцыі, напрыклад \"Ok Google\"\n\n"<annotation id="url">"Даведацца больш"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"У рэжыме эканоміі зараду ўключаецца цёмная тэма і абмяжоўваюцца ці выключаюцца дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і функцыі, напрыклад \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"У рэжыме эканоміі зараду ўключаецца цёмная тэма і выключаюцца ці абмяжоўваюцца дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і пэўныя функцыі.\n\n"<annotation id="url">"Даведацца больш"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"У рэжыме эканоміі зараду ўключаецца цёмная тэма і выключаюцца ці абмяжоўваюцца дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і пэўныя функцыі."</string>
<string name="data_saver_description" msgid="4995164271550590517">"У рэжыме \"Эканомія трафіка\" фонавая перадача для некаторых праграмам адключана. Праграма, якую вы зараз выкарыстоўваеце, можа атрымліваць доступ да даных, але радзей, чым звычайна. Напрыклад, відарысы могуць не загружацца, пакуль вы не націсніце на іх."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Уключыць Эканомію трафіка?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Уключыць"</string>
@@ -2139,12 +2151,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Гэта апавяшчэнне пераведзена ў рэжым \"Без гуку\". Націсніце тут і дайце водгук."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Гэта апавяшчэнне ацэнена як важнае. Націсніце тут і дайце водгук."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Гэта апавяшчэнне ацэнена як няважнае. Націсніце тут і дайце водгук."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Палепшаныя апавяшчэнні"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Каб і далей атрымліваць прапановы дзеянняў, адказаў і іншага змесціва, уключыце палепшаныя апавяшчэнні. Адаптыўныя апавяшчэнні Android больш не падтрымліваюцца."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Уключыць"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Не зараз"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Даведацца больш"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Палепшаныя апавяшчэнні маюць доступ да змесціва ўсіх апавяшчэнняў, у тым ліку да асабістай інфармацыі – імён кантактаў і паведамленняў. Гэта функцыя таксама можа адхіляць апавяшчэнні ці актываваць у іх кнопкі дзеянняў, у тым ліку адказваць на тэлефонныя выклікі.\n\nГэта функцыя можа ўключаць і выключаць прыярытэтны рэжым, а таксама змяняць звязаныя налады."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Апавяшчэнне з інфармацыяй пра ўсталяваны рэжым"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Акумулятар можа разрадзіцца хутчэй, чым прыйдзе час звычайнай зарадкі"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Каб павялічыць тэрмін работы акумулятара, уключаны рэжым эканоміі зараду"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 5b8a81c..307f4ab 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Неизвестен вертикален формат"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Неизвестен хоризонтален формат"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Анулирано"</string>
@@ -1852,10 +1864,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Актуализирано от администратора ви"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Изтрито от администратора ви"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Режимът за запазване на батерията включва тъмната тема и ограничава или изключва активността на заден план, някои визуални ефекти и различни функции, като например „Ok Google“.\n\n"<annotation id="url">"Научете повече"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Режимът за запазване на батерията включва тъмната тема и ограничава или изключва активността на заден план, някои визуални ефекти и различни функции, като например „Ok Google“."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Режимът за запазване на батерията включва тъмната тема и ограничава или изключва активността на заден план, някои визуални ефекти и определени функции.\n\n"<annotation id="url">"Научете повече"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Режимът за запазване на батерията включва тъмната тема и ограничава или изключва активността на заден план, някои визуални ефекти и определени функции."</string>
<string name="data_saver_description" msgid="4995164271550590517">"С цел намаляване на преноса на данни функцията за икономия на данни не позволява на някои приложения да изпращат или получават данни на заден план. Понастоящем използвано от вас приложение може да използва данни, но по-рядко. Това например може да означава, че изображенията не се показват, докато не ги докоснете."</string>
- <string name="data_saver_enable_title" msgid="7080620065745260137">"Ще вкл. ли „Икономия на данни“?"</string>
+ <string name="data_saver_enable_title" msgid="7080620065745260137">"Включване на „Икономия на данни“?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Включване"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
<item quantity="other">За %1$d минути (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Това известие бе понижено до беззвучно. Докоснете, за да изпратите отзиви."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Това известие бе класирано по-високо. Докоснете, за да изпратите отзиви."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Това известие бе класирано по-ниско. Докоснете, за да изпратите отзиви."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Изпробвайте подобрен. известия"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"За да продължите да получавате предложени действия, отговори и др., включете функцията за подобрени известия. Адаптивните известия за Android вече не се поддържат."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Включване"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Не сега"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Подобрени известия"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Предложените действия и отговори вече се предоставят от функцията за подобрени известия. Адаптивните известия за Android вече не се поддържат."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Изключване"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Научете повече"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Функцията за подобрени известия може да чете цялото съдържание в дадено известие, включително личната информация, като например имената на контактите и текстовите съобщения. Тя има възможност да отхвърля известията или да предприема действия по бутоните в тях, като например приемане на телефонни обаждания.\n\nСъщо така функцията може да включва или изключва приоритетния режим и да променя сродни настройки."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Адаптивните известия бяха заменени от функцията за подобрени известия в Android 12. Тя показва предложени действия и отговори и организира известията ви.\n\nФункцията може да осъществява достъп до съдържанието в известията, включително личната информация, като например имената на контактите и текстовите съобщения. Тя има възможност да отхвърля известията или да предприема действия в тях, като например приемане на телефонни обаждания или контролиране на режима „Не безпокойте“."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Известие с информация за режима на поредица"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батерията може да се изтощи преди обичайното зареждане"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Режимът за запазване на батерията е активиран с цел удължаване на живота на батерията"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 21cf141..d41bcb9 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,8 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <!-- no translation found for mediasize_japanese_l (1326765321473431817) -->
+ <skip />
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"অজানা পোর্ট্রেট"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"অজানা ল্যান্ডস্কেপ"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"বাতিল করা হয়েছে"</string>
@@ -1852,8 +1865,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"আপনার প্রশাসক আপডেট করেছেন"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"আপনার প্রশাসক মুছে দিয়েছেন"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"ব্যাটারি সেভার ডার্ক থিম চালু করে এবং ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট এবং “Ok Google”-এর মতো ফিচার সীমিত করে বা বন্ধ করে দেয়\n\n"<annotation id="url">"আরও জানুন"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"ব্যাটারি সেভার ডার্ক থিম চালু করে এবং ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট এবং “Ok Google”-এর মতো ফিচার সীমিত করে বা বন্ধ করে দেয়।"</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (5693741424234005958) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"ডেটার ব্যবহার কমাতে সহায়তা করার জন্য, ডেটা সেভার ব্যাকগ্রাউন্ডে কিছু অ্যাপ্লিকেশনকে ডেটা পাঠাতে বা গ্রহণ করতে বাধা দেয়৷ আপনি বর্তমানে এমন একটি অ্যাপ্লিকেশন ব্যবহার করছেন যেটি ডেটা অ্যাক্সেস করতে পারে, তবে সেটি কমই করে৷ এর ফলে যা হতে পারে, উদাহরণস্বরূপ, আপনি ছবির উপর ট্যাপ না করা পর্যন্ত সেগুলি দেখানো হবে না৷"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ডেটা সেভার চালু করবেন?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"চালু করুন"</string>
@@ -2073,12 +2088,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"এই বিজ্ঞপ্তির গুরুত্ব কমিয়ে মিউট হিসেবে সেট করা হয়েছে। মতামত জানাতে ট্যাপ করুন।"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"এই বিজ্ঞপ্তির গুরুত্ব বাড়ানো হয়েছে। মতামত জানাতে ট্যাপ করুন।"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"এই বিজ্ঞপ্তির গুরুত্ব কমানো হয়েছে। মতামত জানাতে ট্যাপ করুন।"</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"উন্নত নোটিফিকেশন ব্যবহার করুন"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"সাজেস্ট করা অ্যাকশন, উত্তর এবং আরও অনেক কিছু পাওয়া চালিয়ে যেতে, উন্নত নোটিফিকেশন পাওয়ার সুবিধা চালু করুন। Android অ্যাডাপ্টিভ নোটিফিকেশন আর কাজ করবে না।"</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"চালু করুন"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"এখন নয়"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"আরও জানুন"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"উন্নত নোটিফিকেশন পরিচিতির নাম এবং মেসেজের মতো ব্যক্তিগত তথ্য ছাড়াও নোটিফিকেশনের সবকটি কন্টেন্ট পড়তে পারবে। এছাড়াও, এই ফিচার নোটিফিকেশন বাতিল করতে পারবে এবং নোটিফিকেশনে থাকা বোতামের সাহায্যে অ্যাকশন নিতে পারবে, যেমন ফোন কলের উত্তর দেওয়া।\n\nএই ফিচার প্রায়োরিটি মোড চালু বা বন্ধ করতে এবং সেই সম্পর্কিত সেটিংস পরিবর্তনও করতে পারবে।"</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"রুটিন মোডের তথ্য সংক্রান্ত বিজ্ঞপ্তি"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"সাধারণত যখন চার্জ দেন, তার আগে চার্জ শেষ হয়ে যেতে পারে"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ডিভাইস বেশিক্ষণ চালু রাখতে ব্যাটারি সেভার চালু করা হয়েছে"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index b0a9726..c776cac 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1795,6 +1795,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1831,6 +1842,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Neodređeni uspravni format"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Neodređeni vodoravni format"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Otkazano"</string>
@@ -1875,8 +1887,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je vaš administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je vaš administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Uredu"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnosti u pozadini, određene vizuelne efekte i funkcije kao što je \"Ok Google\"\n\n"<annotation id="url">"Saznajte više"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnosti u pozadini, određene vizuelne efekte i funkcije kao što je \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i neke funkcije.\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i neke funkcije."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Radi smanjenja prijenosa podataka, Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali će to činiti rjeđe. Naprimjer, to može značiti da se slike ne prikazuju dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Uključiti Uštedu podataka?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Uključi"</string>
@@ -2106,12 +2118,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Značaj ovog obavještenja je umanjen na Nečujno. Dodirnite da pošaljete povratne informacije."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Značaj ovog obavještenja je povećan. Dodirnite da pošaljete povratne informacije."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Značaj ovog obavještenja je umanjen. Dodirnite da pošaljete povratne informacije."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Probajte poboljšana obavještenja"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Da nastavite primati prijedloge radnji, odgovore i još mnogo toga, uključite poboljšana obavještenja. Prilagodljiva obavještenja Androida više nisu podržana."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Uključi"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ne sada"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Poboljšana obavještenja"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Poboljšana obavještenja sada pružaju predložene radnje i odgovore. Prilagodljiva obavještenja Androida više nisu podržana."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Uredu"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Isključi"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saznajte više"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Poboljšana obavještenja mogu čitati sav sadržaj obavještenja, uključujući lične informacije kao što su imena kontakata i poruke. Ova funkcija također može odbaciti obavještenja ili poduzeti radnje vezane za dugmad u obavještenjima, kao što je javljanje na telefonske pozive.\n\nOva funkcija također može uključiti ili isključiti način rada Prioriteti i promijeniti srodne postavke."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Poboljšana obavještenja su zamijenila Prilagodljiva obavještenja Androida u verziji Android 12. Ova funkcija prikazuje predložene radnje i odgovore te organizira vaša obavještenja.\n\nPoboljšana obavještenja mogu pristupiti sadržaju obavještenja, uključujući lične informacije kao što su imena kontakata i poruke. Ova funkcija također može odbacivati obavještenja ili odgovarati na njih, npr. može odgovarati na telefonske pozive i kontrolirati funkciju Ne ometaj."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Obavještenje za informacije Rutinskog načina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Moguće je da će se baterija isprazniti prije uobičajenog punjenja"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Ušteda baterije je aktivirana da bi se produžio vijek trajanja baterije"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index f098fbe..a581de6 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quart"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foli"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Vertical desconegut"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Horitzontal desconegut"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancel·lada"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualitzat per l\'administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Suprimit per l\'administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"D\'acord"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Estalvi de bateria activa el tema fosc i limita o desactiva l\'activitat en segon pla, alguns efectes visuals i funcions com \"Hey Google\".\n\n"<annotation id="url">"Més informació"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Estalvi de bateria activa el tema fosc i limita o desactiva l\'activitat en segon pla, alguns efectes visuals i funcions com \"Hey Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Estalvi de bateria activa el tema fosc i limita o desactiva l\'activitat en segon pla, alguns efectes visuals i determinades funcions.\n\n"<annotation id="url">"Més informació"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Estalvi de bateria activa el tema fosc i limita o desactiva l\'activitat en segon pla, alguns efectes visuals i determinades funcions."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Per reduir l\'ús de dades, la funció Economitzador de dades evita que determinades aplicacions enviïn o rebin dades en segon pla. L\'aplicació que estiguis fent servir podrà accedir a les dades, però menys sovint. Això vol dir, per exemple, que les imatges no es mostraran fins que no les toquis."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activar l\'Economitzador de dades?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activa"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"El nivell d\'aquesta notificació s\'ha disminuït a Silenci. Toca per proporcionar suggeriments."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Aquesta notificació s\'ha classificat amb un nivell superior. Toca per proporcionar suggeriments."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Aquesta notificació s\'ha classificat amb un nivell inferior. Toca per proporcionar suggeriments."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Prova notificacions millorades"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Per continuar rebent accions suggerides, respostes i més, activa les notificacions millorades. Les notificacions adaptatives d\'Android ja no s\'admeten."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Activa"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ara no"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notificacions millorades"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Ara, les accions i respostes suggerides les proporcionen les notificacions millorades. Les notificacions adaptatives d\'Android ja no s\'admeten."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"D\'acord"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desactiva"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Més informació"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Les notificacions millorades poden llegir tot el contingut de les notificacions, inclosa la informació personal com els noms dels contactes i els missatges. Aquesta funció també pot ignorar les notificacions o fer accions amb els botons de les notificacions, com ara contestar a trucades.\n\nA més, pot activar i desactivar el mode Prioritat i canviar-ne la configuració."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Les notificacions millorades han substituït les notificacions adaptatives d\'Android a Android 12. Aquesta funció mostra les accions i respostes suggerides, i organitza les teves notificacions.\n\nLes notificacions millorades poden accedir al contingut de les notificacions, inclosa la informació personal com els noms dels contactes i els missatges. Aquesta funció també pot ignorar les notificacions o respondre-hi, com ara contestar trucades o controlar el mode No molestis."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificació d\'informació del mode de rutina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"És possible que la bateria s\'esgoti abans de la càrrega habitual"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"S\'ha activat l\'estalvi de bateria per prolongar-ne la durada"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index de6debb..c562a8f 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1817,6 +1817,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1853,6 +1864,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Neznámý formát na výšku"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Neznámý formát na šířku"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Zrušeno"</string>
@@ -1898,8 +1910,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizováno administrátorem"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Smazáno administrátorem"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Spořič baterie zapne tmavý motiv a omezí nebo vypne aktivitu na pozadí, některé vizuální efekty a funkce jako „Ok Google“\n\n"<annotation id="url">"Další informace"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Spořič baterie zapne tmavý motiv a omezí nebo vypne aktivitu na pozadí, některé vizuální efekty a funkce jako „Ok Google“."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Spořič baterie zapíná tmavý motiv a omezuje či vypíná aktivitu na pozadí, některé vizuální efekty a některé funkce.\n\n"<annotation id="url">"Další informace"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Spořič baterie zapíná tmavý motiv a omezuje či vypíná aktivitu na pozadí, některé vizuální efekty a některé funkce."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Z důvodu snížení využití dat brání spořič dat některým aplikacím v odesílání nebo příjmu dat na pozadí. Aplikace, kterou právě používáte, data přenášet může, ale může tak činit méně často. V důsledku toho se například obrázky nemusejí zobrazit, dokud na ně neklepnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Chcete zapnout Spořič dat?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Zapnout"</string>
@@ -2139,12 +2151,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Toto oznámení bylo ztlumeno. Po klepnutí můžete zadat zpětnou vazbu."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"U tohoto oznámení byla zvýšena priorita. Po klepnutí můžete zadat zpětnou vazbu."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"U tohoto oznámení byla snížena priorita. Po klepnutí můžete zadat zpětnou vazbu."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Vyzkoušejte vylepšená oznámení"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Pokud chcete dál dostávat návrhy akcí, odpovědí a další, zapněte vylepšená oznámení. Adaptivní oznámení systému Android už nejsou podporována."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Zapnout"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Teď ne"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Vylepšená oznámení"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Navrhované akce a odpovědi jsou teď poskytovány prostřednictvím vylepšených oznámení. Adaptivní oznámení systému Android už nejsou podporována."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Vypnout"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Další informace"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Vylepšená oznámení mohou číst veškerý obsah oznámení včetně osobních údajů, jako jsou jména kontaktů a obsah zpráv. Tato funkce také může zavírat oznámení nebo aktivovat tlačítka v oznámeních, například přijímat telefonické hovory.\n\nMůže také zapnout nebo vypnout prioritní režim a změnit související nastavení."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Adaptivní oznámení pro Android byla v systému Android 12 nahrazena vylepšenými oznámeními. Tato funkce ukazuje navrhované akce a odpovědi a uspořádává oznámení.\n\nVylepšená oznámení mají přístup k obsahu oznámení, včetně osobních údajů, jako jsou jména kontaktů a zprávy. Tato funkce také může zavírat oznámení nebo na ně odpovídat, například přijímat telefonní hovory a ovládat režim Nerušit."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Informační oznámení režimu sledu činností"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterie se možná vybije před obvyklým časem nabití"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Byl aktivován spořič baterie za účelem prodloužení výdrže"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 557484d..9f4f5a0 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1708,7 +1708,7 @@
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Deaktiver genvej"</string>
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Brug genvej"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Ombytning af farver"</string>
- <string name="color_correction_feature_name" msgid="3655077237805422597">"Korriger farve"</string>
+ <string name="color_correction_feature_name" msgid="3655077237805422597">"Farvekorrigering"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra dæmpet belysning"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Lydstyrkeknapperne blev holdt nede. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er aktiveret."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Lydstyrkeknapperne blev holdt nede. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er deaktiveret."</string>
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Ukendt stående format"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Ukendt liggende format"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Annulleret"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Opdateret af din administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet af din administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Batterisparefunktionen aktiverer Mørkt tema og deaktiverer eller begrænser aktivitet i baggrunden, visse visuelle effekter og funktioner som f.eks. \"Hey Google\"\n\n"<annotation id="url">"Få flere oplysninger"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Batterisparefunktionen aktiverer Mørkt tema og deaktiverer eller begrænser aktivitet i baggrunden, visse visuelle effekter og funktioner som f.eks. \"Hey Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Batterisparefunktion aktiverer Mørkt tema og begrænser eller deaktiverer aktivitet i baggrunden, nogle visuelle effekter og visse funktioner.\n\n"<annotation id="url">"Få flere oplysninger"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Batterisparefunktion aktiverer Mørkt tema og begrænser eller deaktiverer aktivitet i baggrunden, nogle visuelle effekter og visse funktioner."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Datasparefunktionen forhindrer nogle apps i at sende eller modtage data i baggrunden for at reducere dataforbruget. En app, der er i brug, kan få adgang til data, men gør det måske ikke så ofte. Dette kan f.eks. betyde, at billeder ikke vises, før du trykker på dem."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vil du aktivere Datasparefunktion?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivér"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Denne notifikation blev angivet som Lydløs. Tryk for at give feedback."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Denne notifikation blev placeret højere. Tryk for at give feedback."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Denne notifikation blev placeret lavere. Tryk for at give feedback."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Prøv forbedrede notifikationer"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Aktivér forbedrede notifikationer for at fortsætte med at få forslag til handlinger, svar og meget mere. Tilpassede Android-notifikationer understøttes ikke længere."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aktivér"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ikke nu"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Få flere oplysninger"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Forbedrede notifikationer kan læse alt indhold i notifikationer, bl.a. personlige oplysninger som f.eks. beskeder og navne på kontakter. Denne funktion kan også afvise notifikationer eller aktivere knapper i notifikationer, herunder besvare opkald.\n\nDenne funktion kan også aktivere og deaktivere tilstanden Prioritet samt ændre relaterede indstillinger."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notifikation med oplysninger om rutinetilstand"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Enheden løber muligvis tør for batteri, inden du normalt oplader den"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterisparefunktion er aktiveret for at forlænge batteritiden"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 04b5747..f14273b 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,8 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <!-- no translation found for mediasize_japanese_l (1326765321473431817) -->
+ <skip />
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Unbekannt – Hochformat"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Unbekannt – Querformat"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Abgebrochen"</string>
@@ -1852,8 +1865,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Von deinem Administrator aktualisiert"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Von deinem Administrator gelöscht"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Der Energiesparmodus aktiviert das dunkle Design und schränkt Hintergrundaktivitäten, einige optische Effekte und Funktionen wie „Hey Google“ ein oder schaltet diese ab\n\n"<annotation id="url">"Weitere Informationen"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Der Energiesparmodus aktiviert das dunkle Design und schränkt Hintergrundaktivitäten, einige optische Effekte und Funktionen wie „Hey Google“ ein oder schaltet diese ab."</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (5693741424234005958) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"Der Datensparmodus verhindert zum einen, dass manche Apps im Hintergrund Daten senden oder empfangen, sodass weniger Daten verbraucht werden. Zum anderen werden die Datenzugriffe der gerade aktiven App eingeschränkt, was z. B. dazu führen kann, dass Bilder erst angetippt werden müssen, bevor sie sichtbar werden."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Datensparmodus aktivieren?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivieren"</string>
@@ -2073,12 +2088,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Diese Benachrichtigung wurde auf „Lautlos“ herabgestuft. Tippe, um Feedback zu geben."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Diese Benachrichtigung wurde hochgestuft. Tippe, um Feedback zu geben."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Diese Benachrichtigung wurde herabgestuft. Tippe, um Feedback zu geben."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"„Erweiterte Benachrichtigungen“ ausprobieren"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Wenn du weiterhin beispielsweise Vorschläge für Aktionen und Antworten erhalten möchtest, aktiviere die Funktion „Erweiterte Benachrichtigungen“. Adaptive Benachrichtigungen für Android werden nicht mehr unterstützt."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aktivieren"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Nicht jetzt"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Weitere Informationen"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Die Funktion „Erweiterte Benachrichtigungen“ kann alle Benachrichtigungen lesen, darunter auch personenbezogene Daten wie Kontaktnamen und Nachrichten. Außerdem kann sie Benachrichtigungen schließen oder Schaltflächen in Benachrichtigungen verwenden und so beispielsweise Anrufe entgegennehmen.\n\nDiese Funktion kann auch den Prioritätsmodus aktivieren bzw. deaktivieren und zugehörige Einstellungen ändern."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Infomitteilung zum Ablaufmodus"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Dein Akku könnte vor der gewöhnlichen Ladezeit leer sein"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Energiesparmodus aktiviert, um die Akkulaufzeit zu verlängern"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 417b8f2..1defb40 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"Μ"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Άγνωστος κατακόρυφος προσανατολισμός"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Άγνωστος οριζόντιος προσανατολισμός"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Ακυρώθηκε"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ενημερώθηκε από τον διαχειριστή σας"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Διαγράφηκε από τον διαχειριστή σας"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Η Εξοικονόμηση μπαταρίας ενεργοποιεί το Σκούρο θέμα και περιορίζει ή απενεργοποιεί τη δραστηριότητα στο παρασκήνιο, ορισμένα οπτικά εφέ και λειτουργίες όπως την εντολή \"Ok Google\"\n\n"<annotation id="url">"Μάθετε περισσότερα"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Η Εξοικονόμηση μπαταρίας ενεργοποιεί το Σκούρο θέμα και περιορίζει ή απενεργοποιεί τη δραστηριότητα στο παρασκήνιο, ορισμένα οπτικά εφέ και λειτουργίες όπως την εντολή \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Η Εξοικονόμηση μπαταρίας ενεργοποιεί το Σκούρο θέμα και περιορίζει ή απενεργοποιεί τη δραστηριότητα στο παρασκήνιο, ορισμένα οπτικά εφέ και συγκεκριμένες λειτουργίες.\n\n"<annotation id="url">"Μάθετε περισσότερα"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Η Εξοικονόμηση μπαταρίας ενεργοποιεί το Σκούρο θέμα και περιορίζει ή απενεργοποιεί τη δραστηριότητα στο παρασκήνιο, ορισμένα οπτικά εφέ και συγκεκριμένες λειτουργίες."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Προκειμένου να μειωθεί η χρήση δεδομένων, η Εξοικονόμηση δεδομένων αποτρέπει την αποστολή ή λήψη δεδομένων από ορισμένες εφαρμογές στο παρασκήνιο. Μια εφαρμογή που χρησιμοποιείτε αυτήν τη στιγμή μπορεί να χρησιμοποιήσει δεδομένα αλλά με μικρότερη συχνότητα. Για παράδειγμα, οι εικόνες μπορεί να μην εμφανίζονται μέχρι να τις πατήσετε."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ενεργ.Εξοικονόμησης δεδομένων;"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ενεργοποίηση"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Αυτή η ειδοποίηση υποβιβάστηκε στις Αθόρυβες. Πατήστε για να υποβάλετε σχόλια."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Αυτή η ειδοποίηση κατατάχθηκε ψηλότερα. Πατήστε για να υποβάλετε σχόλια."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Αυτή η ειδοποίηση κατατάχθηκε χαμηλότερα. Πατήστε για να υποβάλετε σχόλια."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Δοκιμή βελτιωμ. ειδοποιήσεων"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Για να συνεχίσετε να λαμβάνετε προτεινόμενες ενέργειες, απαντήσεις και άλλα, ενεργοποιήστε τις βελτιωμένες ειδοποιήσεις. Δεν υποστηρίζονται πλέον οι Προσαρμοστικές ειδοποιήσεις Android."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Ενεργοποίηση"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Όχι τώρα"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Βελτιωμένες ειδοποιήσεις"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Οι προτεινόμενες ενέργειες και απαντήσεις παρέχονται πλέον από βελτιωμένες ειδοποιήσεις. Δεν υποστηρίζονται πλέον οι Προσαρμοστικές ειδοποιήσεις Android."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ΟΚ"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Απενεργοποίηση"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Μάθετε περισσότερα"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Οι Βελτιωμένες ειδοποιήσεις έχουν τη δυνατότητα ανάγνωσης όλου του περιεχομένου ειδοποιήσεων, συμπεριλαμβανομένων των προσωπικών πληροφοριών, όπως ονομάτων επαφών και μηνυμάτων. Αυτή η λειτουργία έχει επίσης τη δυνατότητα παράβλεψης ειδοποιήσεων ή λήψης ενεργειών σε κουμπιά στις ειδοποιήσεις, όπως η απάντηση τηλεφωνικών κλήσεων.\n\nΕπίσης, έχει τη δυνατότητα ενεργοποίησης ή απενεργοποίησης της λειτουργίας Προτεραιότητας, καθώς και αλλαγής των σχετικών ρυθμίσεων."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Στο Android 12, οι Βελτιωμένες ειδοποιήσεις αντικατέστησαν τις Προσαρμοστικές ειδοποιήσεις Android. Αυτή η λειτουργία εμφανίζει προτεινόμενες ενέργειες και απαντήσεις και οργανώνει τις ειδοποιήσεις σας.\n\nΟι Βελτιωμένες ειδοποιήσεις μπορούν να αποκτήσουν πρόσβαση σε περιεχόμενο ειδοποιήσεων, συμπεριλαμβανομένων προσωπικών στοιχείων, όπως ονομάτων επαφών και μηνυμάτων. Αυτή η λειτουργία παρέχει επίσης τη δυνατότητα παράβλεψης ή απάντησης ειδοποιήσεων, όπως η απάντηση σε τηλεφωνικές κλήσεις και ο έλεγχος της λειτουργίας Μην ενοχλείτε."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ειδοποίηση πληροφοριών λειτουργίας Ρουτίνας"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Η μπαταρία μπορεί να εξαντληθεί πριν από τη συνηθισμένη φόρτιση"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Η Εξοικονόμηση μπαταρίας ενεργοποιήθηκε για την επέκταση της διάρκειας ζωής της μπαταρίας"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index f8ca0b1..f123c8e 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Unknown portrait"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Unknown landscape"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelled"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and features like \'Hey Google\'\n\n"<annotation id="url">"Learn more"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and features like \'Hey Google\'."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features.\n\n"<annotation id="url">"Learn more"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features."</string>
<string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you\'re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"This notification was demoted to silent. Tap to provide feedback."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"This notification was ranked higher. Tap to provide feedback."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"This notification was ranked lower. Tap to provide feedback."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Try enhanced notifications"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"To keep getting suggested actions, replies and more, turn on enhanced notifications. Android Adaptive Notifications are no longer supported."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Turn on"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Not now"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Enhanced notifications"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Suggested actions and replies are now provided by enhanced notifications. Android adaptive notifications are no longer supported."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Turn off"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Learn more"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Enhanced notifications can read all notification content, including personal information like contact names and messages. This feature can also dismiss notifications or take actions on buttons in notifications, such as answering phone calls.\n\nThis feature can also turn Priority mode on or off and change related settings."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Enhanced notifications replaced Android adaptive notifications in Android 12. This feature shows suggested actions and replies, and organises your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls and controlling Do Not Disturb."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery may run out before usual charge"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Battery Saver activated to extend battery life"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index dc993fe..686bb39 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Unknown portrait"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Unknown landscape"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelled"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and features like \'Hey Google\'\n\n"<annotation id="url">"Learn more"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and features like \'Hey Google\'."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features.\n\n"<annotation id="url">"Learn more"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features."</string>
<string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you\'re currently using can access data, but may do so less frequently. This may mean, for example, that images don\'t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"This notification was demoted to silent. Tap to provide feedback."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"This notification was ranked higher. Tap to provide feedback."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"This notification was ranked lower. Tap to provide feedback."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Try enhanced notifications"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"To keep getting suggested actions, replies and more, turn on enhanced notifications. Android Adaptive Notifications are no longer supported."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Turn on"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Not now"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Enhanced notifications"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Suggested actions and replies are now provided by enhanced notifications. Android adaptive notifications are no longer supported."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Turn off"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Learn more"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Enhanced notifications can read all notification content, including personal information like contact names and messages. This feature can also dismiss notifications or take actions on buttons in notifications, such as answering phone calls.\n\nThis feature can also turn Priority mode on or off and change related settings."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Enhanced notifications replaced Android adaptive notifications in Android 12. This feature shows suggested actions and replies, and organises your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls and controlling Do Not Disturb."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery may run out before usual charge"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Battery Saver activated to extend battery life"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 5b80a90..c8728ad 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Unknown portrait"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Unknown landscape"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelled"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and features like \'Hey Google\'\n\n"<annotation id="url">"Learn more"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and features like \'Hey Google\'."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features.\n\n"<annotation id="url">"Learn more"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features."</string>
<string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"This notification was demoted to silent. Tap to provide feedback."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"This notification was ranked higher. Tap to provide feedback."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"This notification was ranked lower. Tap to provide feedback."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Try enhanced notifications"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"To keep getting suggested actions, replies and more, turn on enhanced notifications. Android Adaptive Notifications are no longer supported."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Turn on"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Not now"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Enhanced notifications"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Suggested actions and replies are now provided by enhanced notifications. Android adaptive notifications are no longer supported."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Turn off"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Learn more"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Enhanced notifications can read all notification content, including personal information like contact names and messages. This feature can also dismiss notifications or take actions on buttons in notifications, such as answering phone calls.\n\nThis feature can also turn Priority mode on or off and change related settings."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Enhanced notifications replaced Android adaptive notifications in Android 12. This feature shows suggested actions and replies, and organises your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls and controlling Do Not Disturb."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery may run out before usual charge"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Battery Saver activated to extend battery life"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index dad96b4..4e71212 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Unknown portrait"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Unknown landscape"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelled"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and features like \'Hey Google\'\n\n"<annotation id="url">"Learn more"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and features like \'Hey Google\'."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features.\n\n"<annotation id="url">"Learn more"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features."</string>
<string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"This notification was demoted to silent. Tap to provide feedback."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"This notification was ranked higher. Tap to provide feedback."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"This notification was ranked lower. Tap to provide feedback."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Try enhanced notifications"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"To keep getting suggested actions, replies and more, turn on enhanced notifications. Android Adaptive Notifications are no longer supported."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Turn on"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Not now"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Enhanced notifications"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Suggested actions and replies are now provided by enhanced notifications. Android adaptive notifications are no longer supported."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Turn off"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Learn more"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Enhanced notifications can read all notification content, including personal information like contact names and messages. This feature can also dismiss notifications or take actions on buttons in notifications, such as answering phone calls.\n\nThis feature can also turn Priority mode on or off and change related settings."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Enhanced notifications replaced Android adaptive notifications in Android 12. This feature shows suggested actions and replies, and organises your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls and controlling Do Not Disturb."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery may run out before usual charge"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Battery Saver activated to extend battery life"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 2cdf5ba..e6887e9 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Unknown portrait"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Unknown landscape"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelled"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, and features like “Hey Google”\n\n"<annotation id="url">"Learn more"</annotation>""</string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, and features like “Hey Google”."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, and certain features.\n\n"<annotation id="url">"Learn more"</annotation>""</string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, and certain features."</string>
<string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"This notification was demoted to Silent. Tap to provide feedback."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"This notification was ranked higher. Tap to provide feedback."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"This notification was ranked lower. Tap to provide feedback."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Try enhanced notifications"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"To keep getting suggested actions, replies, and more, turn on enhanced notifications. Android Adaptive Notifications are no longer supported."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Turn on"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Not now"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Enhanced notifications"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Suggested actions and replies are now provided by enhanced notifications. Android Adaptive Notifications are no longer supported."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Turn off"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Learn more"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Enhanced notifications can read all notification content, including personal information like contact names and messages. This feature can also dismiss notifications or take actions on buttons in notifications, such as answering phone calls.\n\nThis feature can also turn Priority mode on or off and change related settings."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Enhanced notifications replaced Android Adaptive Notifications in Android 12. This feature shows suggested actions and replies, and organizes your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls and controlling Do Not Disturb."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery may run out before usual charge"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Battery Saver activated to extend battery life"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 6a1cddc..e25d927 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -266,7 +266,7 @@
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"El sonido está Desactivado"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"El sonido está Activado"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="6911684460146916206">"Modo avión"</string>
+ <string name="global_actions_toggle_airplane_mode" msgid="6911684460146916206">"Modo de avión"</string>
<string name="global_actions_airplane_mode_on_status" msgid="5508025516695361936">"El modo avión está Activado"</string>
<string name="global_actions_airplane_mode_off_status" msgid="8522219771500505475">"El modo avión está Desactivado"</string>
<string name="global_action_settings" msgid="4671878836947494217">"Configuración"</string>
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarca"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Cuartilla"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Folio"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Cualquier tamaño vertical"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Cualquier tamaño horizontal"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelada"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Tu administrador actualizó este paquete"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Tu administrador borró este paquete"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"El Ahorro de batería activa el Tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Hey Google\"\n\n"<annotation id="url">"Más información"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"El Ahorro de batería activa el Tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Hey Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"El Ahorro de batería activa el Tema oscuro y desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones determinadas.\n\n"<annotation id="url">"Más información"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"El Ahorro de batería activa el Tema oscuro y desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones determinadas."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para reducir el uso de datos, el modo Ahorro de datos evita que algunas apps envíen y reciban datos en segundo plano. La app que estés usando podrá acceder a los datos, pero con menor frecuencia. De esta forma, por ejemplo, las imágenes no se mostrarán hasta que las presiones."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"¿Deseas activar Ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Esta notificación descendió de a Silenciada. Presiona para enviar comentarios."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Esta notificación recibió una clasificación superior. Presiona para enviar comentarios."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Esta notificación recibió una clasificación inferior. Presiona para enviar comentarios."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Prueba las notif. mejoradas"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Activa las notificaciones mejoradas para seguir recibiendo acciones sugeridas, respuestas y mucho más. Ya no se admiten las notificaciones adaptables de Android."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Activar"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ahora no"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Más información"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Las notificaciones mejoradas pueden leer todo el contenido de notificaciones, incluido el que contenga información personal, como nombres de contactos y mensajes. Esta función también podrá descartar notificaciones o realizar acciones en botones de notificaciones, como responder llamadas.\n\nTambién puede activar o desactivar el Modo prioridad y cambiar la configuración relacionada."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificación de información del modo de Rutinas"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Es posible que la batería se agote antes de la carga habitual"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Se activó el Ahorro de batería para extender la duración de la batería"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 7519b5a..a28553a 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Cualquier tamaño vertical"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Cualquier tamaño horizontal"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelado"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado por el administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado por el administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Ahorro de batería activa el tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales y funciones como \"Hey Google\"\n\n"<annotation id="url">"Más información"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Ahorro de batería activa el tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales y funciones como \"Hey Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Ahorro de batería activa el tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales y ciertas funciones.\n\n"<annotation id="url">"Más información"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Ahorro de batería activa el tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales y ciertas funciones."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que puede reducir el uso de datos. Una aplicación que estés usando de forma activa puede acceder a los datos, aunque con menos frecuencia. Esto significa que es posible que, por ejemplo, algunas imágenes no se muestren hasta que las toques."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"¿Activar Ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"La importancia de esta notificación ha disminuido a Silencio. Toca para enviar comentarios."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Esta notificación aparecerá en una posición más alta. Toca para enviar comentarios."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Esta notificación aparecerá en una posición más baja. Toca para enviar comentarios."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Probar notificaciones mejoradas"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Para seguir recibiendo sugerencias de acciones, respuestas y más, activa las notificaciones mejoradas. Las notificaciones adaptativas de Android ya no están disponibles."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Activar"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ahora no"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Más información"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Las notificaciones mejoradas pueden leer todo el contenido de las notificaciones, incluidas las relacionadas con información personal, como nombres y mensajes de tus contactos. Esta función también puede cerrar notificaciones o utilizar los botones de las notificaciones, por ejemplo, para responder llamadas telefónicas.\n\nAdemás, puede activar o desactivar el modo Prioridad y cambiar ajustes relacionados con él."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificación sobre el modo rutina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Quizás se agote la batería antes de lo habitual"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Se ha activado el modo Ahorro de batería para aumentar la duración de la batería"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 1e58aed..b464f93 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Tundmatu vertikaalpaigutuses"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Tundmatu horisontaalpaigutuses"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Tühistatud"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administraator on seda värskendanud"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administraator on selle kustutanud"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Akusäästja lülitab sisse tumeda teema ning piirab taustategevusi, teatud visuaalseid efekte ja funktsioone, nagu „Ok Google“ (või lülitab need välja)\n\n"<annotation id="url">"Lisateave"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Akusäästja lülitab sisse tumeda teema ning piirab taustategevusi, teatud visuaalseid efekte ja funktsioone, nagu „Ok Google“ (või lülitab need välja)."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Akusäästja lülitab sisse tumeda teema ja lülitab välja taustategevused, mõned visuaalsed efektid ja teatud funktsioonid või piirab neid.\n\n"<annotation id="url">"Lisateave"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Akusäästja lülitab sisse tumeda teema ja lülitab välja taustategevused, mõned visuaalsed efektid ja teatud funktsioonid või piirab neid."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Andmekasutuse vähendamiseks keelab andmemahu säästja mõne rakenduse puhul andmete taustal saatmise ja vastuvõtmise. Rakendus, mida praegu kasutate, pääseb andmesidele juurde, kuid võib seda teha väiksema sagedusega. Seetõttu võidakse näiteks pildid kuvada alles siis, kui neid puudutate."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Lülitada andmemahu säästja sisse?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Lülita sisse"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Sellele märguandele määrati prioriteet Vaikne. Puudutage tagasiside andmiseks."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Sellele märguandele määrati kõrgem prioriteet. Puudutage tagasiside andmiseks."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Sellele märguandele määrati madalam prioriteet. Puudutage tagasiside andmiseks."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Proovige täiustatud märguandeid"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Soovitatud toimingute, vastuste ja muu nägemiseks ka edaspidi lülitage sisse täiustatud märguanded. Androidi kohanduvaid märguandeid enam ei toetata."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Lülita sisse"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Mitte praegu"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Lisateave"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Täiustatud märguanded saavad lugeda kogu märguande sisu, sh isiklikku teavet, nagu kontaktide nimed ja sõnumid. Samuti saab selle funktsiooniga märguannetest loobuda või märguannetes nuppude abil toiminguid teha (nt vastata telefonikõnedele).\n\nLisaks saab selle funktsiooniga sisse või välja lülitada režiimi Prioriteetne ja muuta seotud seadeid."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutiinirežiimi teabe märguanne"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Aku võib enne tavapärast laadimist tühjaks saada"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Akusäästja aktiveeriti aku tööea pikendamiseks"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index ce10584..a6859ed 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch (AEB)"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto (AEB)"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap (AEB)"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K (Txina)"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K (Txina)"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1 (Txina)"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu (Japonia)"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2 (Japonia)"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4 (Japonia)"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Bertikal ezezaguna"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Horizontal ezezaguna"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Bertan behera utzi da"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administratzaileak eguneratu du"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratzaileak ezabatu du"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Ados"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Bateria-aurrezleak gai iluna aktibatzen du, eta murriztu edo desaktibatu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta beste eginbide batzuk, hala nola \"Ok Google\".\n\n"<annotation id="url">"Lortu informazio gehiago"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Bateria-aurrezleak gai iluna aktibatzen du, eta murriztu edo desaktibatu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta beste eginbide batzuk, hala nola \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Bateria-aurrezleak gai iluna aktibatzen du, eta murriztu edo desaktibatu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta eginbide jakin batzuk.\n\n"<annotation id="url">"Lortu informazio gehiago"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Bateria-aurrezleak gai iluna aktibatzen du, eta murriztu edo desaktibatu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta eginbide jakin batzuk."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Datuen erabilera murrizteko, atzeko planoan datuak bidaltzea eta jasotzea galarazten die datu-aurrezleak aplikazio batzuei. Une honetan erabiltzen ari zaren aplikazio batek datuak atzitu ahal izango ditu, baina baliteke maiztasun txikiagoarekin atzitzea. Horrela, adibidez, baliteke irudiak ez erakustea haiek sakatu arte."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Datu-aurrezlea aktibatu nahi duzu?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktibatu"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Isilarazi da jakinarazpena. Sakatu hau oharrak bidaltzeko."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Mailaz igo da jakinarazpena. Sakatu hau oharrak bidaltzeko."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Mailaz jaitsi da jakinarazpena. Sakatu hau oharrak bidaltzeko."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Probatu jakinarazpen hobetuak"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Iradokitako ekintzak, erantzunak eta abar jasotzen jarraitzeko, aktibatu jakinarazpen hobetuak. Android-en jakinarazpen egokituak ez dira onartzen jada."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aktibatu"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Orain ez"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Jakinarazpen hobetuak"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Orain, jakinarazpen hobetuen bitartez iradokitzen dira ekintzak eta erantzunak. Android-eko jakinarazpen egokituak ez dira onartzen jada."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Ados"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desaktibatu"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Lortu informazio gehiago"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Jakinarazpen hobetuek jakinarazpenen eduki osoa irakur dezakete, informazio pertsonala barne (esaterako, kontaktuen izenak eta mezuak). Halaber, jakinarazpenak baztertu edo jakinarazpenetako botoiak erabil ditzake eginbideak; adibidez, telefono-deiak erantzun.\n\nHorretaz gain, lehentasunezko modua aktibatu edo desaktiba dezake, eta erlazionatutako ezarpenak aldatu."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12n, jakinarazpen hobetuek ordeztu dituzte Android-eko jakinarazpen egokituak. Eginbide horrek, iradokitako ekintzak eta erantzunak erakutsi, eta zure jakinarazpenak antolatzen ditu.\n\nJakinarazpen hobetuek jakinarazpenen eduki osoa atzi dezakete, informazio pertsonala barne (esaterako, kontaktuen izenak eta mezuak). Halaber, jakinarazpenak baztertu edo haiei erantzun diezaieke eginbideak; adibidez, telefono-deiak erantzun eta ez molestatzeko modua kontrolatu."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ohitura moduaren informazio-jakinarazpena"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baliteke bateria ohi baino lehenago agortzea"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Bateria-aurrezlea aktibatuta dago bateriaren iraupena luzatzeko"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 280c71f..472ea61 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -542,10 +542,10 @@
<string name="permdesc_bluetooth_advertise" product="default" msgid="6085174451034210183">"برنامه مجاز میشود در دستگاههای بلوتوث اطراف تبلیغ کند."</string>
<string name="permlab_uwb_ranging" msgid="8141915781475770665">"مشخص کردن موقعیت نسبی بین دستگاههای باند فوقوسیع اطراف"</string>
<string name="permdesc_uwb_ranging" msgid="2519723069604307055">"به برنامه اجازه داده میشود موقعیت نسبی بین دستگاههای باند فوقوسیع اطراف را مشخص کند"</string>
- <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"اطلاعات ترجیحی سرویس پولی «ارتباط میدان نزدیک» (NFC)"</string>
- <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"به برنامه اجازه میدهد اطلاعات ترجیحی سرویس پولی «ارتباط میدان نزدیک» (NFC)، مانند کمکهای ثبتشده و مقصد مسیر را دریافت کند."</string>
+ <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"اطلاعات ترجیحی سرویس پولی NFC"</string>
+ <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"به برنامه اجازه میدهد اطلاعات ترجیحی سرویس پولی NFC، مانند کمکهای ثبتشده و مقصد مسیر را دریافت کند."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"کنترل ارتباط راه نزدیک"</string>
- <string name="permdesc_nfc" msgid="8352737680695296741">"به برنامه اجازه میدهد تا با تگهای «ارتباط میدان نزدیک» (NFC)، کارتها و فایلخوان ارتباط برقرار کند."</string>
+ <string name="permdesc_nfc" msgid="8352737680695296741">"به برنامه اجازه میدهد تا با تگهای NFC، کارتها و فایلخوان ارتباط برقرار کند."</string>
<string name="permlab_disableKeyguard" msgid="3605253559020928505">"غیرفعال کردن قفل صفحه شما"</string>
<string name="permdesc_disableKeyguard" msgid="3223710003098573038">"به برنامه امکان میدهد قفل کلید و هر گونه امنیت گذرواژه مرتبط را غیرفعال کند. بهعنوان مثال تلفن هنگام دریافت یک تماس تلفنی ورودی قفل کلید را غیرفعال میکند و بعد از پایان تماس، قفل کلید را دوباره فعال میکند."</string>
<string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"درخواست پیچیدگی قفل صفحه"</string>
@@ -712,7 +712,7 @@
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"حذف گواهیهای DRM"</string>
<string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"به برنامه امکان میدهد گواهیهای DRM را حذف کند. نباید برای برنامههای عادی هیچوقت لازم باشد."</string>
<string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"مقید به سرویس پیامرسانی شرکت مخابراتی"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"به کنترلکننده اجازه میدهد که به سطح بالای رابط کاربر سرویس پیامرسانی شرکت مخابراتی مقید شود. هرگز نباید برای برنامههای عادی مورد نیاز شود."</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"به کنترلکننده اجازه میدهد که به سطح بالای میانای کاربر سرویس پیامرسانی شرکت مخابراتی مقید شود. هرگز نباید برای برنامههای عادی مورد نیاز شود."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"اتصال به سرویسهای شرکت مخابراتی"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"به دارنده امکان میدهد به سرویسهای شرکت مخابراتی متصل شود. هرگز نباید برای برنامههای عادی مورد نیاز باشد."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"دسترسی به حالت «مزاحم نشوید»"</string>
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"بزرگ"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"عمودی نامشخص"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"افقی نامشخص"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"لغو شد"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"توسط سرپرست سیستم بهروزرسانی شد"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"توسط سرپرست سیستم حذف شد"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"تأیید"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"«بهینهسازی باتری» «طرح زمینه تیره» را روشن میکند و فعالیت پسزمینه، برخی از جلوههای بصری، و ویژگیهایی مثل «Ok Google» را محدود یا خاموش میکند.\n\n"<annotation id="url">"بیشتر بدانید"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"«بهینهسازی باتری» «طرح زمینه تیره» را روشن میکند و فعالیت پسزمینه، برخی از جلوههای بصری، و ویژگیهایی مثل «Ok Google» را محدود یا خاموش میکند."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"«بهینهسازی باتری» «طرح زمینه تیره» را روشن میکند و فعالیت پسزمینه، برخی از جلوههای بصری، و ویژگیهایی خاص را محدود یا خاموش میکند.\n\n"<annotation id="url">"بیشتر بدانید"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"«بهینهسازی باتری» «طرح زمینه تیره» را روشن میکند و فعالیت پسزمینه، برخی از جلوههای بصری، و ویژگیهایی خاص را محدود یا خاموش میکند."</string>
<string name="data_saver_description" msgid="4995164271550590517">"برای کمک به کاهش مصرف داده، «صرفهجویی داده» از ارسال و دریافت داده در پسزمینه در بعضی برنامهها جلوگیری میکند. برنامهای که درحالحاضر استفاده میکنید میتواند به دادهها دسترسی داشته باشد اما دفعات دسترسی آن محدود است. این میتواند به این معنی باشد که، برای مثال، تصاویر تازمانیکه روی آنها ضربه نزنید نشان داده نمیشوند."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"«صرفهجویی داده» روشن شود؟"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"روشن کردن"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"این اعلان به «بیصدا» تنزل داده شد. برای ارائه بازخورد، ضربه بزنید."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"این اعلان در رتبه بالاتری قرار گرفت. برای ارائه بازخورد، ضربه بزنید."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"این اعلان در رتبه پایینتری قرار گرفت. برای ارائه بازخورد، ضربه بزنید."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"امتحان کردن اعلانهای بهبودیافته"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"برای اینکه پاسخها و کنشهای پیشنهادی و موارد دیگر را همچنان دریافت کنید، اعلانهای بهبودیافته را روشن کنید. از «اعلانهای تطبیقی Android» دیگر پشتیبانی نمیشود."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"روشن کردن"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"الآن نه"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"اعلانهای بهبودیافته"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"اکنون پاسخها و کنشهای پیشنهادی ازطریق اعلانهای بهبودیافته ارائه میشوند. «اعلانهای تطبیقی Android» دیگر پشتیبانی نمیشوند."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"تأیید"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"خاموش کردن"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"بیشتر بدانید"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"اعلانهای بهبودیافته میتواند محتوای همه اعلانها، ازجمله اطلاعات شخصی مثل نام مخاطبین و پیامها را بخواند. این ویژگی همچنین میتواند اعلانها را ببندد یا بااستفاده از دکمههای موجود در اعلانها اقداماتی انجام دهد، مثلاً به تماسهای تلفنی پاسخ دهد.\n\nبهعلاوه، این ویژگی میتواند «حالت اولویت» را روشن یا خاموش کند و تنظیمات مربوطه را تغییر دهد."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"در Android نسخه ۱۲، اعلانهای بهبودیافته جایگزین «اعلانهای تطبیقی» شده است. این ویژگی پاسخها و کنشهای پیشنهادی را نمایش میدهد و اعلانهایتان را سازماندهی میکند.\n\nاعلانهای بهبودیافته میتوانند به محتوای اعلان، ازجمله اطلاعات شخصی مثل نامها و پیامهای مخاطبین دسترسی داشته باشند. این ویژگی همچنین میتواند اعلانها را رد کند یا به آنها پاسخ دهد؛ مثلاً پاسخ به تماسهای تلفنی و کنترل کردن «مزاحم نشوید»."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"اعلان اطلاعات حالت روال معمول"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ممکن است شارژ باتری قبل از شارژ معمول تمام شود"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"جهت افزایش عمر باتری، «بهینهسازی باتری» فعال شد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 2538e86..c51bd26 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch (184 mm x 267 mm)"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto (203 mm x 254 mm)"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap (203 mm x 330 mm)"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K (270 mm x 390 mm)"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K (195 mm x 270 mm)"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1 (102 mm x 165 mm)"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu (240 mm x 322,1 mm)"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2 (240 mm x 332 mm)"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4 (105 mm x 235 mm)"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Tuntematon pystykoko"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Tuntematon vaakakoko"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Peruutettu"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Järjestelmänvalvoja päivitti tämän."</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Järjestelmänvalvoja poisti tämän."</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Virransäästö laittaa tumman teeman päälle ja rajoittaa tai laittaa pois päältä taustatoimintoja, joitakin visuaalisia tehosteita ja muita ominaisuuksia (esim. Ok Google).\n\n"<annotation id="url">"Lue lisää"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Virransäästö laittaa tumman teeman päälle ja rajoittaa tai laittaa pois päältä taustatoimintoja, joitakin visuaalisia tehosteita ja muita ominaisuuksia (esim. Ok Google)."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Virransäästö laittaa tumman teeman päälle ja laittaa pois päältä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja tiettyjä muita ominaisuuksia.\n\n"<annotation id="url">"Lue lisää"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Virransäästö laittaa tumman teeman päälle ja laittaa pois päältä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja tiettyjä muita ominaisuuksia."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Data Saver estää joitakin sovelluksia lähettämästä tai vastaanottamasta tietoja taustalla, jotta datan käyttöä voidaan vähentää. Käytössäsi oleva sovellus voi yhä käyttää dataa, mutta se saattaa tehdä niin tavallista harvemmin. Tämä voi tarkoittaa esimerkiksi sitä, että kuva ladataan vasta, kun kosketat sitä."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Otetaanko Data Saver käyttöön?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ota käyttöön"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Tämä ilmoitus hiljennettiin. Lähetä palautetta napauttamalla."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Tämän ilmoituksen tasoa nostettiin. Lähetä palautetta napauttamalla."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Tämän ilmoituksen tasoa laskettiin. Lähetä palautetta napauttamalla."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Kokeile parann. ilmoituksia"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Jos haluat jatkossakin saada ehdotuksia toiminnoista, vastauksista ja muista, laita parannetut ilmoitukset päälle. Androidin mukautuvia ilmoituksia ei enää tueta."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Laita päälle"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ei nyt"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Parannetut ilmoitukset"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Parannetut ehdotukset tarjoavat nyt toiminto- ja vastausehdotuksia. Androidin mukautuvia ilmoituksia ei enää tueta."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Laita pois päältä"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Lue lisää"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Parannetut ilmoitukset voivat lukea kaikkea ilmoitussisältöä, myös henkilökohtaisia tietoja (esim. kontaktien nimet ja viestit). Ominaisuus voi myös ohittaa ilmoituksia tai käyttää niiden toimintopainikkeita, esim. vastata puheluihin.\n\nLisäksi ominaisuus voi laittaa Tärkeät-tilan päälle tai pois päältä ja muuttaa siihen liittyviä asetuksia."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Parannetut ilmoitukset korvasivat Androidin mukautuvat ilmoitukset Android 12:ssa. Tämä ominaisuus näyttää toiminto- ja vastausehdotuksia ja järjestää ilmoituksesi.\n\nParannetuilla ilmoituksilla on pääsy kaikkeen ilmoitussisältöön, myös henkilökohtaisiin tietoihin (esim. kontaktien nimet ja viestit). Tämä ominaisuus voi myös ohittaa ilmoituksia tai vastata niihin, esim. vastata puheluihin ja ohjata Älä häiritse ‑tilaa."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ohjelmatilan tietoilmoitus"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akku saattaa loppua ennen normaalia latausaikaa"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Virransäästö otettu käyttöön akunkeston pidentämiseksi"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index a5b1250..886c613 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarque"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"In-quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Taille inconnue au format portrait"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Taille inconnue au format paysage"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Annulé"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Mise à jour par votre administrateur"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"La fonctionnalité Économiseur de pile active le mode sombre et limite ou désactive l\'activité en arrière-plan, certains effets visuels et certaines fonctionnalités, comme « Ok Google »\n\n"<annotation id="url">"En savoir plus"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"La fonctionnalité Économiseur de pile active le mode sombre et limite ou désactive l\'activité en arrière-plan, certains effets visuels et certaines fonctionnalités, comme « Ok Google »."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"La fonctionnalité Économiseur de pile active le thème sombre et limite ou désactive l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités.\n\n"<annotation id="url">"En savoir plus"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"La fonctionnalité Économiseur de pile active le thème sombre et limite ou désactive l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Pour aider à diminuer l\'utilisation des données, la fonctionnalité Économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Une application que vous utilisez actuellement peut accéder à des données, mais peut le faire moins souvent. Cela peut signifier, par exemple, que les images ne s\'affichent pas jusqu\'à ce que vous les touchiez."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'économiseur de données?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Cette notification a été rétrogradée à Silencieuse. Touchez pour envoyer des commentaires."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Cette notification a été élevée d\'un niveau. Touchez pour envoyer des commentaires."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Cette notification a été abaissée d\'un niveau. Touchez pour envoyer des commentaires."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Essayer les notif. améliorées"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Pour continuer de recevoir des suggestions d\'actions, de réponses et plus encore, activez les notifications améliorées. Les notifications adaptatives Android ne sont plus prises en charge."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Activer"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Plus tard"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"En savoir plus"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Les notifications améliorées peuvent lire le contenu de toutes les notifications, y compris les renseignements personnels comme le nom des contacts et les messages. Cette fonctionnalité peut aussi fermer des notifications ou effectuer des actions sur les boutons dans les notifications, comme répondre aux appels entrants.\n\nElle peut aussi activer et désactiver le mode Prioritaire et modifier les paramètres connexes."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notification d\'information du mode Routine"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"La pile pourrait s\'épuiser avant la charge habituelle"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Le mode Économiseur de pile est activé afin de prolonger l\'autonomie"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 86cc13a..9524cd5 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,8 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <!-- no translation found for mediasize_japanese_l (1326765321473431817) -->
+ <skip />
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Taille inconnue au format portrait"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Taille inconnue au format paysage"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Tâche annulée."</string>
@@ -1852,8 +1865,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Mis à jour par votre administrateur"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"L\'économiseur de batterie active le thème sombre et limite ou désactive les activités en arrière-plan, certains effets visuels et d\'autres fonctionnalités comme \"Hey Google\"\n\n"<annotation id="url">"En savoir plus"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"L\'économiseur de batterie active le thème sombre et limite ou désactive les activités en arrière-plan, certains effets visuels et d\'autres fonctionnalités comme \"Hey Google\"."</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (5693741424234005958) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"Pour réduire la consommation des données, l\'Économiseur de données empêche certaines applis d\'envoyer ou de recevoir des données en arrière-plan. Les applis que vous utiliserez pourront toujours accéder aux données, mais le feront moins fréquemment. Par exemple, les images pourront ne pas s\'afficher tant que vous n\'aurez pas appuyé pas dessus."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'économiseur de données ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string>
@@ -2073,12 +2088,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Cette notification a été abaissée à la catégorie \"Silencieux\". Appuyez ici pour donner votre avis."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Cette notification a été élevée d\'un niveau. Appuyez ici pour donner votre avis."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Cette notification a été abaissée d\'un niveau. Appuyez ici pour donner votre avis."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Testez les notifications améliorées"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Activez les notifications améliorées pour continuer à recevoir des suggestions d\'actions, de réponses et plus encore. Les notifications intelligentes Android ne sont plus disponibles."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Activer"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Pas maintenant"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"En savoir plus"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Les notifications améliorées peuvent lire tout le contenu des notifications, y compris des informations personnelles comme le nom des contacts et les messages. Cette fonctionnalité peut aussi fermer des notifications ou effectuer des actions grâce aux boutons figurant dans ces notifications, par exemple répondre aux appels téléphoniques.\n\nElle peut aussi activer ou désactiver le mode Prioritaire et modifier les paramètres associés."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notification d\'information du mode Routine"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Vous risquez d\'être à court de batterie plus tôt que prévu"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Économiseur de batterie activé pour prolonger l\'autonomie"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 25fb55c..13cbdb3 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Tamaño folio"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Retrato descoñecido"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Paisaxe descoñecida"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelada"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado polo teu administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado polo teu administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Coa función Aforro de batería actívase o tema escuro e restrínxense ou desactívanse a actividade en segundo plano, algúns efectos visuais e outras funcións, como “Hey Google”\n\n"<annotation id="url">"Máis información"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Coa función Aforro de batería actívase o tema escuro e restrínxense ou desactívanse a actividade en segundo plano, algúns efectos visuais e outras funcións, como “Hey Google”."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Coa función Aforro de batería actívase o tema escuro e restrínxense ou desactívanse a actividade en segundo plano, algúns efectos visuais e determinadas funcións.\n\n"<annotation id="url">"Máis información"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Coa función Aforro de batería actívase o tema escuro e restrínxense ou desactívanse a actividade en segundo plano, algúns efectos visuais e determinadas funcións."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para contribuír a reducir o uso de datos, o aforro de datos impide que algunhas aplicacións envíen ou reciban datos en segundo plano. Cando esteas utilizando unha aplicación, esta poderá acceder aos datos, pero é posible que o faga con menos frecuencia. Por exemplo, poida que as imaxes non se mostren ata que as toques."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Queres activar o aforro de datos?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"O nivel desta notificación diminuíu a Silenciosa. Toca para compartir a túa opinión."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Esta notificación clasificouse nun nivel superior. Toca para compartir a túa opinión."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Esta notificación clasificouse nun nivel inferior. Toca para compartir a túa opinión."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Proba notificacións melloradas"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Para seguir recibindo accións suxeridas, respostas e moito máis, activa as notificacións melloradas. As notificacións intelixentes de Android xa non son compatibles."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Activar"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Agora non"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notificacións melloradas"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Agora, as notificacións melloradas son as que che ofrecen suxestións de accións e respostas. As notificacións intelixentes de Android xa non son compatibles."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Aceptar"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desactivar"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Máis información"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Coas notificacións melloradas pódese ler todo o contido das notificacións, mesmo a información persoal (por exemplo, os nomes dos contactos e as mensaxes). Con esta función tamén se poden ignorar as notificacións ou realizar accións nos botóns que aparecen nelas, como responder chamadas telefónicas.\n\nAdemais, permite activar e desactivar o modo de prioridade e cambiar a configuración relacionada."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"En Android 12, as notificacións melloradas substitúen as notificacións intelixentes. Esta función ofréceche suxestións de accións e respostas, ademais de organizar as notificacións.\n\nEste servizo pode acceder ao contido das notificacións, mesmo á información persoal, como os nomes dos contactos e as mensaxes. Ademais, esta función pode ignorar ou responder as notificacións (por exemplo, coller chamadas telefónicas e controlar o modo Non molestar)."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificación da información do modo de rutina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"A batería pode esgotarse antes do habitual"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Para ampliar a duración da batería activouse a función Aforro de batería"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index f8de931..af0c553 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"મોનાર્ક"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"ક્વાર્ટો"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"ફૂલસ્કેપ"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"રૉક 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,8 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"કહુ"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"કાકુ2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <!-- no translation found for mediasize_japanese_l (1326765321473431817) -->
+ <skip />
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"અજાણ્યું પોર્ટ્રેટ"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"અજાણ્યું લેન્ડસ્કેપ"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"રદ થઈ"</string>
@@ -1852,8 +1865,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ કરવામાં આવેલ છે"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"તમારા વ્યવસ્થાપક દ્વારા કાઢી નાખવામાં આવેલ છે"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ઓકે"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"બૅટરી સેવર ઘેરી થીમની સુવિધા ચાલુ કરે છે અને બૅકગ્રાઉન્ડમાં થતી પ્રવૃત્તિ, કેટલીક વિઝ્યુઅલ ઇફેક્ટ અને “Ok Google” જેવી સુવિધાઓને મર્યાદિત કે બંધ કરે છે\n\n"<annotation id="url">"વધુ જાણો"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"બૅટરી સેવર ઘેરી થીમની સુવિધા ચાલુ કરે છે અને બૅકગ્રાઉન્ડમાં થતી પ્રવૃત્તિ, કેટલીક વિઝ્યુઅલ ઇફેક્ટ અને “Ok Google” જેવી સુવિધાઓને મર્યાદિત કે બંધ કરે છે."</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (5693741424234005958) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"ડેટા વપરાશને ઘટાડવામાં સહાય માટે, ડેટા સેવર કેટલીક ઍપને બૅકગ્રાઉન્ડમાં ડેટા મોકલવા અથવા પ્રાપ્ત કરવાથી અટકાવે છે. તમે હાલમાં ઉપયોગ કરી રહ્યાં છો તે ઍપ ડેટાને ઍક્સેસ કરી શકે છે, પરંતુ તે આ ક્યારેક જ કરી શકે છે. આનો અર્થ એ હોઈ શકે છે, ઉદાહરણ તરીકે, છબીઓ ત્યાં સુધી પ્રદર્શિત થશે નહીં જ્યાં સુધી તમે તેને ટૅપ નહીં કરો."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ડેટા સેવર ચાલુ કરીએ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ચાલુ કરો"</string>
@@ -2073,12 +2088,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"નોટિફિકેશનને સાઇલન્ટ પર અવનત કરવામાં આવ્યું. પ્રતિસાદ આપવા માટે ટૅપ કરો."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"આ નોટિફિકેશનને ઉપલી રેંક આપવામાં આવી. પ્રતિસાદ આપવા માટે ટૅપ કરો."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"આ નોટિફિકેશનને નીચલી રેંક આપવામાં આવી. પ્રતિસાદ આપવા માટે ટૅપ કરો."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"વધારાના નોટિફિકેશન અજમાવી જુઓ"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"સૂચવેલી ક્રિયાઓ, જવાબો અને બીજું ઘણું મેળવવા માટે, વધારાના નોટિફિકેશન ચાલુ કરો. Android માટે અનુકૂળ નોટિફિકેશનને હવેથી સપોર્ટ કરવામાં આવતો નથી."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ચાલુ કરો"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"હમણાં નહીં"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"વધુ જાણો"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"વધારાના નોટિફિકેશન સંપર્કનું નામ અને સંદેશા જેવી વ્યક્તિગત માહિતી સહિત નોટિફિકેશનનું બધું કન્ટેન્ટ વાંચી શકે છે. આ સુવિધા નોટિફિકેશન છોડી પણ શકે છે અથવા નોટિફિકેશનમાં બટન પર ફોન કૉલનો જવાબ આપવા જેવી ક્રિયાઓ પણ કરી શકે છે.\n\nઆ સુવિધા પ્રાધાન્યતા મોડ ચાલુ કે બંધ પણ કરી શકે છે અને સંબંધિત સેટિંગ બદલી પણ શકે છે."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"રૂટિન મોડની માહિતીનું નોટિફિકેશન"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"સામાન્ય રીતે ચાર્જ કરવાના સમય પહેલાં બૅટરી સમાપ્ત થઈ શકે છે"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"બૅટરી આવરદા વધારવા માટે બૅટરી સેવર ચાલુ કર્યું"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 4ab4a7a..866f2ef 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"मोनार्क"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"क्वार्टो"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"फ़ूल्ज़कैप"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"काहु"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"काकु2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"यौ4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"अज्ञात पोर्ट्रेट"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"अज्ञात लैंडस्केप"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"रद्द कर दी गई"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"आपके व्यवस्थापक ने अपडेट किया है"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"आपके व्यवस्थापक ने हटा दिया है"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ठीक है"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"बैटरी सेवर गहरे रंग वाली थीम को चालू कर देता है. साथ ही, यह बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और \"Hey Google\" जैसी दूसरी सुविधाएं इस्तेमाल करने से डिवाइस को रोकता है या इन्हें बंद कर देता है\n\n"<annotation id="url">"ज़्यादा जानें"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"बैटरी सेवर गहरे रंग वाली थीम को चालू कर देता है. साथ ही, यह बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और \"Hey Google\" जैसी दूसरी सुविधाएं इस्तेमाल करने से डिवाइस को रोकता है या इन्हें बंद कर देता है."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"बैटरी सेवर, गहरे रंग वाली थीम को चालू कर देता है. साथ ही, यह बैकग्राउंड में चल रही गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और कुछ खास सुविधाएं इस्तेमाल करने से रोकता है या इन्हें बंद कर देता है.\n\n"<annotation id="url">"ज़्यादा जानें"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"बैटरी सेवर, गहरे रंग वाली थीम को चालू कर देता है. साथ ही, यह बैकग्राउंड में चल रही गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और कुछ खास सुविधाओं के इस्तेमाल को रोकता है या इन्हें बंद कर देता है."</string>
<string name="data_saver_description" msgid="4995164271550590517">"डेटा खर्च को कम करने के लिए, डेटा बचाने की सेटिंग कुछ ऐप्लिकेशन को बैकग्राउंड में डेटा भेजने या डेटा पाने से रोकती है. फ़िलहाल, आप जिस ऐप्लिकेशन का इस्तेमाल कर रहे हैं वह डेटा ऐक्सेस कर सकता है, लेकिन ऐसा कभी-कभी ही हो पाएगा. उदाहरण के लिए, इमेज तब तक दिखाई नहीं देंगी जब तक कि आप उन पर टैप नहीं करते."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा बचाने की सेटिंग चालू करें?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"चालू करें"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"इस सूचना के मिलने पर होने वाली आवाज़ बंद कर दी गई है. सुझाव/शिकायत/राय देने के लिए टैप करें."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"इस सूचना को रैंकिंग में ऊपर किया गया था. सुझाव/शिकायत/राय देने के लिए टैप करें."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"इस सूचना को रैंकिंग में नीचे किया गया था. सुझाव/शिकायत/राय देने के लिए टैप करें."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"\'बेहतर सूचनाएं\' सुविधा आज़माएं"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"कार्रवाई और जवाब वगैरह के लिए सुझाव पाना चाहते हैं, तो सूचनाएं पाने की सुविधा बेहतर करें. Android की, ज़रूरत के हिसाब से सूचनाएं पाने की सुविधा अब काम नहीं करती है."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"चालू करें"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"अभी नहीं"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ज़्यादा जानें"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"\'बेहतर सूचनाएं\' सुविधा, डिवाइस पर मिलने वाली सभी सूचनाओं का कॉन्टेंट पढ़ सकती है. इसमें आपकी निजी जानकारी, जैसे कि संपर्कों के नाम और मैसेज भी शामिल हैं. यह सुविधा, डिवाइस पर आने वाली सूचनाओं को रद्द कर सकती है या सूचनाओं में दिखने वाले बटन से कार्रवाइयां भी कर सकती है, जैसे कि फ़ोन कॉल का जवाब देना.\n\nयह सुविधा, प्राथमिकता मोड को चालू या बंद कर सकती है और इससे जुड़ी सेटिंग में बदलाव भी कर सकती है."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"रूटीन मोड जानकारी की सूचना"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"बैटरी आम तौर पर जितने समय चलती है, उससे पहले खत्म हो सकती है"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"बैटरी लाइफ़ बढ़ाने के लिए \'बैटरी सेवर\' चालू हो गया है"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 28fb400..7bc5eda 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1731,7 +1731,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Upotrijebi prečac"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija boja"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Korekcija boja"</string>
- <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Dodatno zatamnjenje"</string>
+ <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Još tamnije"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tipke za glasnoću. Uključila se usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tipke za glasnoću. Isključila se usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite i zadržite tipke za glasnoću na tri sekunde da biste koristili uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1795,6 +1795,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1831,6 +1842,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Nepoznati portret"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Nepoznati pejzaž"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Otkazano"</string>
@@ -1875,8 +1887,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"U redu"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Štednja baterije uključuje tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizualne efekte i značajke kao što je Hey Google\n\n"<annotation id="url">"Saznajte više"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Štednja baterije uključuje tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizualne efekte i značajke kao što je Hey Google."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Štednja baterije uključuje tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizualne efekte i određene značajke.\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Štednja baterije uključuje tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizualne efekte i određene značajke."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Da bi se smanjio podatkovni promet, značajka Štednja podatkovnog prometa onemogućuje nekim aplikacijama slanje ili primanje podataka u pozadini. Aplikacija koju trenutačno upotrebljavate može pristupiti podacima, no možda će to činiti rjeđe. To može značiti da se, na primjer, slike neće prikazivati dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Uključiti Štednju podatkovnog prometa?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Uključi"</string>
@@ -2087,7 +2099,7 @@
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"IPAK OTVORI"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Otkrivena je štetna aplikacija"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> želi prikazivati isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
- <string name="screenshot_edit" msgid="7408934887203689207">"Uređivanje"</string>
+ <string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Uređaj će vibrirati za pozive i obavijesti"</string>
<string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Zvučni signal poziva i obavijesti bit će isključen"</string>
<string name="notification_channel_system_changes" msgid="2462010596920209678">"Promjene sustava"</string>
@@ -2106,12 +2118,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Obavijest je degradirana u bešumnu. Dodirnite da biste poslali povratne informacije."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Obavijest je više rangirana. Dodirnite da biste poslali povratne informacije."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Obavijest je niže rangirana. Dodirnite da biste poslali povratne informacije."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Proba poboljšanih obavijesti"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Da biste i dalje primali prijedloge za radnje, odgovore i druge informacije, uključite poboljšane obavijesti. Prilagodljive obavijesti za Android više nisu podržane."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Uključi"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ne sad"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Poboljšane obavijesti"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Predložene radnje i odgovori sad se pružaju putem poboljšanih obavijesti. Prilagodljive obavijesti za Android više nisu podržane."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"U redu"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Isključi"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saznajte više"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Poboljšane obavijesti mogu čitati sadržaj svih obavijesti, uključujući osobne podatke kao što su imena kontakata i poruke. Ta značajka može i odbacivati obavijesti ili poduzimati radnje povezane s gumbima u obavijestima kao što je odgovaranje na telefonske pozive.\n\nZnačajka također može uključiti ili isključiti način prioritetnih obavijesti i promijeniti povezane postavke."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"U Androidu 12 poboljšane obavijesti zamjenjuju prilagodljive obavijesti za Android. Ta značajka prikazuje predložene radnje i odgovore te organizira vaše obavijesti.\n\nPoboljšane obavijesti mogu pristupiti sadržaju obavijesti, uključujući osobne podatke kao što su imena kontakata i poruke. Ta značajka može i odbacivati obavijesti ili poduzimati radnje u skladu s njima, na primjer može odgovarati na telefonske pozive i upravljati značajkom Ne uznemiravaj."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Obavještavanje o informacijama u Rutinskom načinu rada"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterija se može isprazniti prije uobičajenog vremena punjenja"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Štednja baterije aktivirana je kako bi se produljilo trajanje baterije"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 09e56d8..9fa0f28 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"„Monarch” méret"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"„Quarto” méret"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"„Foolscap” méret"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"„ROC 8K” méret"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"„ROC 16K” méret"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"„PRC 1” méret"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"„Kahu” méret"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"„Kaku2” méret"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"„You4” méret"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Ismeretlen álló"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Ismeretlen fekvő"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Törölve"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"A rendszergazda által frissítve"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"A rendszergazda által törölve"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, és korlátozza vagy kikapcsolja a háttérbeli tevékenységeket, bizonyos vizuális effekteket és olyan funkciókat, mint az „Ok Google”.\n\n"<annotation id="url">"További információ"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, és korlátozza vagy kikapcsolja a háttérbeli tevékenységeket, bizonyos vizuális effekteket és olyan funkciókat, mint az „Ok Google”."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, valamint korlátozza vagy kikapcsolja a háttérbeli tevékenységeket, egyes vizuális effekteket és bizonyos funkciókat.\n\n"<annotation id="url">"További információ"</annotation>"."</string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, valamint korlátozza vagy kikapcsolja a háttérbeli tevékenységeket, egyes vizuális effekteket és bizonyos funkciókat."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Az adatforgalom csökkentése érdekében az Adatforgalom-csökkentő megakadályozza, hogy egyes alkalmazások adatokat küldjenek vagy fogadjanak a háttérben. Az Ön által jelenleg használt alkalmazások hozzáférhetnek az adatokhoz, de csak ritkábban. Ez például azt jelentheti, hogy a képek csak rákoppintás után jelennek meg."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Bekapcsolja az Adatforgalom-csökkentőt?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Bekapcsolás"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Ezt az értesítést némára állította a rendszer. Visszajelzés küldéséhez koppintson ide."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Ezt az értesítést előrébb sorolta a rendszer. Visszajelzés küldéséhez koppintson ide."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Ezt az értesítést hátrébb sorolta a rendszer. Visszajelzés küldéséhez koppintson ide."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Bővített értesítés kipróbálása"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Ha továbbra is szeretne kapni javasolt műveleteket, válaszokat és egyebeket, kapcsolja be a bővített értesítéseket. Az androidos alkalmazkodó értesítések már nem támogatottak."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Bekapcsolás"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Most nem"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Bővített értesítések"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Javasolt műveletek és válaszok mostantól bővített értesítésekkel. Az androidos alkalmazkodó értesítések már nem támogatottak."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Kikapcsolás"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"További információ"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"A bővített értesítések minden értesítéstartalmat olvashatnak (így a személyes adatokat, mint például a névjegyek nevét és az üzeneteket is). Ez a funkció emellett elvetheti az értesítéseket, valamint műveleteket végezhet az értesítésekben lévő gombokkal, például felveheti a telefonhívásokat.\n\nEz a funkció a Prioritásos módot is be- vagy kikapcsolhatja, és módosíthatja a kapcsolódó beállításokat."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"A bővített értesítések felváltják az androidos alkalmazkodó értesítéseket az Android 12-es verziójában. Ez a funkció a javasolt műveleteket és válaszokat mutatja, és rendszerezi az értesítéseket.\n\nA bővített értesítések minden értesítéstartalmat olvashatnak (így a személyes adatokat, mint például a névjegyek nevét és az üzeneteket is). Ez a funkció emellett elvetheti az értesítéseket, valamint válaszolhat rájuk, például felveheti a telefonhívásokat, és vezérelheti a Ne zavarjanak módot."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Információs értesítés a rutinmódról"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Előfordulhat, hogy az akkumulátor lemerül a szokásos töltési időszak előtt"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Akkumulátorkímélő mód aktiválva az akkumulátor üzemidejének növelése érdekében"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index d4d18c0..b6d59c6 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Անհայտ դիմանկար"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Անհայտ բնապատկեր"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Չեղարկված է"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Թարմացվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Ջնջվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Եղավ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Մարտկոցի տնտեսումը միացնում է մուգ թեման և սահմանափակում կամ անջատում է ֆոնային գործընթացները, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ, օրինակ՝ «Ok Google» հրահանգի ճանաչումը։\n\n"<annotation id="url">"Իմանալ ավելին"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Մարտկոցի տնտեսումը միացնում է մուգ թեման և սահմանափակում կամ անջատում է ֆոնային գործընթացները, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ, օրինակ՝ «Ok Google» հրահանգի ճանաչումը։"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"«Մարտկոցի տնտեսում» գործառույթը միացնում է մուգ թեման և անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ։\n\n"<annotation id="url">"Իմանալ ավելին"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"«Մարտկոցի տնտեսում» գործառույթը միացնում է մուգ թեման և անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ։"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Թրաֆիկի տնտեսման ռեժիմում որոշ հավելվածների համար տվյալների ֆոնային փոխանցումն անջատված է։ Հավելվածը, որն օգտագործում եք, կարող է տվյալներ փոխանցել և ստանալ, սակայն ոչ այնքան հաճախ: Օրինակ՝ պատկերները կցուցադրվեն միայն դրանց վրա սեղմելուց հետո։"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Միացնե՞լ թրաֆիկի տնտեսումը"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Միացնել"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Այս ծանուցման կարևորության մակարդակը իջեցվել է և դարձել անձայն։ Հպեք՝ կարծիք հայտնելու համար։"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Այս ծանուցման կարևորության մակարդակը բարձրացվել է։ Հպեք՝ կարծիք հայտնելու համար։"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Այս ծանուցման կարևորության մակարդակն իջեցվել է։ Հպեք՝ կարծիք հայտնելու համար։"</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Փորձեք ընդլայնված ծանուցումները"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Միացրեք ընդլայնված ծանուցումները, որպեսզի այսուհետ ևս ստանաք գործողությունների, պատասխանների և այլ առաջարկներ։ Android-ի հարմարվող ծանուցումներն այլևս չեն աջակցվում։"</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Միացնել"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ոչ հիմա"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Իմանալ ավելին"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Ընդլայնված ծանուցումներին հասանելի է բոլոր ծանուցումների պարունակությունը, ներառյալ անձնական տվյալները, օրինակ՝ կոնտակտների անուններն ու հաղորդագրությունները։ Այս գործառույթը կարող է նաև փակել ծանուցումները կամ ակտիվացնել դրանցում առկա կոճակները, այդ թվում՝ պատասխանել հեռախոսազանգերի։\n\nԱյս գործառույթը կարող է նաև միացնել/անջատել «Միայն կարևորները» ռեժիմը և փոխել համապատասխան կարգավորումները։"</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ծանուցում լիցքավորման մասին"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Մարտկոցը կարող է սովորականից շուտ սպառվել"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Մարտկոցի կյանքը երկարացնելու համար ակտիվացվել է մարտկոցի տնտեսման ռեժիմը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 5491214..e782377 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Kuarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Folio"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Potret tidak diketahui"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Lanskap tidak diketahui"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Dibatalkan"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Diupdate oleh admin Anda"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Dihapus oleh admin Anda"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Oke"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Penghemat Baterai mengaktifkan Tema gelap dan membatasi atau menonaktifkan aktivitas di latar belakang, beberapa efek visual, dan fitur seperti “Ok Google”\n\n"<annotation id="url">"Pelajari lebih lanjut"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Penghemat Baterai mengaktifkan Tema gelap dan membatasi atau menonaktifkan aktivitas di latar belakang, beberapa efek visual, dan fitur seperti “Ok Google”."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Penghemat Baterai mengaktifkan Tema gelap dan membatasi atau menonaktifkan aktivitas latar belakang, beberapa efek visual, dan fitur tertentu.\n\n"<annotation id="url">"Pelajari lebih lanjut"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Penghemat Baterai mengaktifkan Tema gelap dan membatasi atau menonaktifkan aktivitas latar belakang, beberapa efek visual, dan fitur tertentu."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Untuk membantu mengurangi penggunaan data, Penghemat Data mencegah beberapa aplikasi mengirim atau menerima data di latar belakang. Aplikasi yang sedang digunakan dapat mengakses data, tetapi frekuensinya agak lebih jarang. Misalnya saja, gambar hanya akan ditampilkan setelah diketuk."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Aktifkan Penghemat Data?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktifkan"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Notifikasi ini didemosikan menjadi Senyap. Ketuk untuk memberikan masukan."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Notifikasi ini diberi peringkat lebih tinggi. Ketuk untuk memberikan masukan."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Notifikasi ini diberi peringkat lebih rendah. Ketuk untuk memberikan masukan."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Coba notifikasi yang disempurnakan"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Untuk terus mendapatkan saran tindakan, balasan, dan lainnya, aktifkan notifikasi yang disempurnakan. Notifikasi Adaptif Android tidak lagi didukung."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aktifkan"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Lain kali"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notifikasi yang ditingkatkan"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Tindakan dan balasan yang disarankan kini diberikan oleh notifikasi yang ditingkatkan. Notifikasi Adaptif Android tidak lagi didukung."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Oke"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Nonaktifkan"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Pelajari lebih lanjut"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Notifikasi yang disempurnakan dapat membaca semua isi notifikasi, termasuk informasi pribadi seperti nama kontak dan pesan. Fitur ini juga dapat menutup notifikasi atau memicu tindakan pada tombol di notifikasi, seperti menjawab panggilan telepon.\n\nFitur ini juga dapat mengaktifkan atau menonaktifkan mode Prioritas dan mengubah setelan terkait."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Notifikasi yang ditingkatkan menggantikan Notifikasi Adaptif Android di Android 12. Fitur ini menunjukkan tindakan dan balasan yang disarankan, dan mengatur notifikasi.\n\nNotifikasi yang ditingkatkan dapat mengakses konten notifikasi, termasuk informasi pribadi seperti nama kontak dan pesan. Fitur ini juga dapat menutup atau merespons notifikasi, seperti menjawab panggilan telepon dan mengontrol Jangan Ganggu."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notifikasi info Mode Rutinitas"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterai mungkin habis sebelum pengisian daya biasanya"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Penghemat Baterai diaktifkan untuk memperpanjang masa pakai baterai"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 4ed6fcc..0a834fa 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Örk A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Örk B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Örk C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Örk D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Örk E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Örk E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Óþekkt skammsnið"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Óþekkt langsnið"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Hætt við"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Kerfisstjóri uppfærði"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Kerfisstjóri eyddi"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Í lagi"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Rafhlöðusparnaður kveikir á dökku þema og takmarkar eða slekkur á bakgrunnsvirkni, tilteknum myndbrellum og eiginleikum eins og „Ok Google“.\n\n"<annotation id="url">"Nánar"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Rafhlöðusparnaður kveikir á dökku þema og takmarkar eða slekkur á bakgrunnsvirkni, tilteknum myndbrellum og eiginleikum eins og „Ok Google“."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Rafhlöðusparnaður kveikir á dökku þema og dregur úr eða slekkur á bakgrunnsvirkni, sumum myndáhrifum og tilteknum eiginleikum.\n\n"<annotation id="url">"Nánar"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Rafhlöðusparnaður kveikir á dökku þema og dregur úr eða slekkur á bakgrunnsvirkni, sumum myndáhrifum og tilteknum eiginleikum."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Gagnasparnaður getur hjálpað til við að draga úr gagnanotkun með því að hindra forrit í að senda eða sækja gögn í bakgrunni. Forrit sem er í notkun getur náð í gögn, en gerir það kannski sjaldnar. Niðurstaðan getur verið að myndir eru ekki birtar fyrr en þú ýtir á þær, svo dæmi sé tekið."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Kveikja á gagnasparnaði?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Kveikja"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Þessi tilkynning var gerð þögul. Ýttu til að senda ábendingu."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Þessi tilkynning fékk hærri stöðu. Ýttu til að senda ábendingu."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Þessi tilkynning fékk lægri stöðu. Ýttu til að senda ábendingu."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Prófa auknar tilkynningar"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Kveiktu á auknum tilkynningum til að halda áfram að fá tillögur að aðgerðum, svörum og fleira. Breytilegar tilkynningar í Android eru ekki lengur studdar."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Kveikja"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ekki núna"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Auknar tilkynningar"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Auknar tilkynningar bjóða nú upp á tillögur að aðgerðum og svörum. Breytilegar tilkynningar í Android eru ekki lengur studdar."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Í lagi"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Slökkva"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Nánar"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Auknar tilkynningar geta lesið allt efni tilkynninga, þar á meðal persónuupplýsingar á borð við nöfn tengiliða og skilaboð. Þessi eiginleiki getur einnig hunsað tilkynningar eða notað hnappa í tilkynningum eins og að svara símtölum.\n\nÞessi eiginleiki getur einnig kveikt og slökkt á forgangsstillingu og breytt tengdum stillingum."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Auknar tilkynningar hafa leyst breytilegar tilkynningar í Android af hólmi í Android 12. Eiginleikinn birtir tillögur að aðgerðum og svörum og flokkar tilkynningar.\n\nAuknar tilkynningar hafa aðgang að efni tilkynninga, þ. á m persónuupplýsingum á borð við nöfn tengiliða og skilaboð. Eiginleikinn getur einnig hunsað eða svarað tilkynningum, til dæmis svarað símtölum og stjórnað „Ónáðið ekki“."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Upplýsingatilkynning aðgerðastillingar"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Rafhlaðan kann að tæmast áður en hún kemst í hleðslu"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Kveikt á rafhlöðusparnaði til að lengja endingu rafhlöðunnar"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 23acc8b..21c7aaa 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Carta protocollo"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Verticale sconosciuto"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Orizzontale sconosciuto"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Annullato"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Aggiornato dall\'amministratore"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminato dall\'amministratore"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"L\'opzione Risparmio energetico attiva il tema scuro e limita o disattiva l\'attività in background, alcuni effetti visivi e funzionalità come \"Hey Google\"\n\n"<annotation id="url">"Scopri di più"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"L\'opzione Risparmio energetico attiva il tema scuro e limita o disattiva l\'attività in background, alcuni effetti visivi e funzionalità come \"Hey Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"La funzionalità Risparmio energetico attiva il tema scuro e limita o disattiva le attività in background, alcuni effetti visivi e funzionalità.\n\n"<annotation id="url">"Scopri di più"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"La funzionalità Risparmio energetico attiva il tema scuro e limita o disattiva le attività in background, alcuni effetti visivi e funzionalità."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Per contribuire a ridurre l\'utilizzo dei dati, la funzione Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Esempio: le immagini non vengono visualizzate finché non le tocchi."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Attivare Risparmio dati?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Attiva"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Questa notifica è stata retrocessa a Silenziosa. Tocca per dare un feedback."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Questa notifica è stata posizionata più in alto. Tocca per dare un feedback."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Questa notifica è stata posizionata più in basso. Tocca per dare un feedback."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Prova le notifiche avanzate"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Per continuare a ricevere suggerimenti di azioni, risposte e altro, attiva le notifiche avanzate. Le notifiche adattive Android non sono più supportate."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Attiva"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Non ora"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notifiche avanzate"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Ora le risposte e le azioni suggerite vengono fornite dalle notifiche avanzate. Le notifiche adattive Android non sono più supportate."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Disattiva"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Scopri di più"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Le notifiche avanzate possono accedere all\'intero contenuto di una notifica, incluse le informazioni personali, come i nomi dei contatti e i messaggi. Questa funzionalità può anche ignorare le notifiche o svolgere azioni sui pulsanti nelle notifiche, come rispondere alle telefonate.\n\nQuesta funzionalità può anche attivare o disattivare la modalità Priorità e modificare le relative impostazioni."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Le notifiche adattive Android sono state sostituite dalle notifiche avanzate in Android 12. Questa funzionalità mostra risposte e azioni suggerite e organizza le tue notifiche.\n\nLe notifiche avanzate possono accedere ai contenuti di una notifica, incluse le informazioni personali, come i nomi dei contatti e i messaggi. Questa funzionalità può anche ignorare le notifiche o rispondervi, ad esempio accettando le telefonate e controllando Non disturbare."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notifica di informazioni sulla modalità Routine"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"La batteria potrebbe esaurirsi prima della ricarica abituale"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Risparmio energetico attivo per far durare di più la batteria"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 5269501..ae0abb4 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1817,6 +1817,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super-B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1853,6 +1864,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"הדפסה לאורך בגודל לא ידוע"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"הדפסה לרוחב בגודל לא ידוע"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"בוטלה"</string>
@@ -1898,8 +1910,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"עודכנה על ידי מנהל המערכת"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"נמחקה על ידי מנהל המערכת"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"אישור"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה ומגבילה או מכבה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות כמו \"Hey Google\"\n\n"<annotation id="url">"מידע נוסף"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה ומגבילה או מכבה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות כמו \"Hey Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה ומגבילה או מכבה את הפעילות ברקע, חלק מהאפקטים החזותיים ותכונות מסוימות.\n\n"<annotation id="url">"מידע נוסף"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה ומגבילה או מכבה את הפעילות ברקע, חלק מהאפקטים החזותיים ותכונות מסוימות."</string>
<string name="data_saver_description" msgid="4995164271550590517">"כדי לסייע בהפחתת השימוש בנתונים, חוסך הנתונים (Data Saver) מונע מאפליקציות מסוימות לשלוח או לקבל נתונים ברקע. אפליקציות שבהן נעשה שימוש כרגע יכולות לגשת לנתונים, אבל בתדירות נמוכה יותר. המשמעות היא, למשל, שתמונות יוצגו רק לאחר שמקישים עליהן."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"להפעיל את חוסך הנתונים?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"הפעלה"</string>
@@ -2139,12 +2151,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ההתראה הזו הורדה בדרגה ל\'שקטה\'. יש להקיש כדי לשלוח משוב."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"דירוג ההתראה הזו הוגבה. יש להקיש כדי לשלוח משוב."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ההתראה הזו דורגה נמוך יותר. יש להקיש כדי לשלוח משוב."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"רוצה לנסות את ההתראות המשופרות?"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"כדי להמשיך לקבל הצעות לפעולות, לתשובות ועוד, יש להפעיל את ההתראות המשופרות. אין יותר תמיכה בהתראות מותאמות ל-Android."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"הפעלה"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"לא עכשיו"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"מידע נוסף"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"כשתכונת ההתראות המשופרות פועלת, המערכת יכולה לקרוא את כל תוכן ההתראות, כולל מידע אישי כמו שמות של אנשי קשר והודעות. כמו כן, התכונה תוכל לסגור התראות או לבצע פעולות שהן כוללות, כמו מענה לשיחות טלפון.\n\nהתכונה תוכל גם להפעיל או להשבית את מצב העדיפות ולשנות את ההגדרות הקשורות."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"התראת מידע לגבי מצב שגרתי"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"הסוללה עלולה להתרוקן לפני המועד הרגיל של הטעינה"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"תכונת החיסכון בסוללה הופעלה כדי להאריך את חיי הסוללה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 3783411..65e1849 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"モナーク"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"クォート"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"フールスキャップ"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,8 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"角2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"洋4"</string>
+ <!-- no translation found for mediasize_japanese_l (1326765321473431817) -->
+ <skip />
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"縦向き不明"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"横向き不明"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"キャンセルされました"</string>
@@ -1852,8 +1865,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"管理者により更新されています"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"管理者により削除されています"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"バッテリー セーバーを有効にすると、ダークテーマが ON になり、バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能が制限されるか OFF になります\n\n"<annotation id="url">"詳細"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"バッテリー セーバーを有効にすると、ダークテーマが ON になり、バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能が制限されるか OFF になります。"</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (5693741424234005958) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"データセーバーは、一部のアプリによるバックグラウンドでのデータ送受信を停止することでデータ使用量を抑制します。使用中のアプリからデータを送受信することはできますが、その頻度は低くなる場合があります。この影響として、たとえば画像はタップしないと表示されないようになります。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"データセーバーを ON にしますか?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ON にする"</string>
@@ -2073,12 +2088,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"この通知の重要度がサイレントに下がりました。タップしてフィードバックをお送りください。"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"この通知の重要度が上がりました。タップしてフィードバックをお送りください。"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"この通知の重要度が下がりました。タップしてフィードバックをお送りください。"</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"拡張通知を使ってみる"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"操作や返信の候補などを利用し続けるには、拡張通知を ON にしてください。Android 通知の自動調整はサポートを終了しました。"</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ON にする"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"後で"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"詳細"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"拡張通知はすべての通知コンテンツにアクセスできます。これには、連絡先の名前などの個人情報やメッセージも含まれます。また、通知を非表示にしたり、電話に出るなど、通知内の操作ボタンを実行したりすることもできます。\n\nまた、この機能は、優先モードの設定を切り替えたり、関連する設定を変更したりすることもできます。"</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ルーティン モード情報の通知"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"通常の充電を行う前に電池が切れる可能性があります"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"電池を長持ちさせるため、バッテリー セーバーが有効になりました"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index ba7beac..b8d1e2d 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"დიდი"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"უცნობი პორტრეტი"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"უცნობი ლანდშაფტი"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"გაუქმებული"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"განახლებულია თქვენი ადმინისტრატორის მიერ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"წაიშალა თქვენი ადმინისტრატორის მიერ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"კარგი"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"ბატარეის დამზოგი ჩართავს მუქ თემას და შეზღუდავს ან გამორთავს ფონურ აქტივობას, ზოგიერთ ვიზუალურ ეფექტს და ისეთ ფუნქციებს, როგორიცაა „Ok Google“\n\n"<annotation id="url">"შეიტყვეთ მეტი"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"ბატარეის დამზოგი ჩართავს მუქ თემას და შეზღუდავს ან გამორთავს ფონურ აქტივობას, ზოგიერთ ვიზუალურ ეფექტს და ისეთ ფუნქციებს, როგორიცაა „Ok Google“."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"ბატარეის დამზოგი ჩართავს მუქ თემას და შეზღუდავს ან გამორთავს ფონურ აქტივობას, ზოგიერთ ვიზუალურ ეფექტსა და გარკვეულ ფუნქციებს.\n\n"<annotation id="url">"შეიტყვეთ მეტი"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"ბატარეის დამზოგი ჩართავს მუქ თემას და შეზღუდავს ან გამორთავს ფონურ აქტივობას, ზოგიერთ ვიზუალურ ეფექტსა და გარკვეულ ფუნქციებს."</string>
<string name="data_saver_description" msgid="4995164271550590517">"მობილური ინტერნეტის მოხმარების შემცირების მიზნით, მონაცემთა დამზოგველი ზოგიერთ აპს ფონურ რეჟიმში მონაცემთა გაგზავნასა და მიღებას შეუზღუდავს. თქვენ მიერ ამჟამად გამოყენებული აპი მაინც შეძლებს მობილურ ინტერნეტზე წვდომას, თუმცა ამას ნაკლები სიხშირით განახორციელებს. ეს ნიშნავს, რომ, მაგალითად, სურათები არ გამოჩნდება მანამ, სანამ მათ საგანგებოდ არ შეეხებით."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ჩაირთოს მონაცემთა დამზოგველი?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ჩართვა"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ეს შეტყობინება ჩამოქვეითდა და გახდა „ჩუმი“. შეეხეთ გამოხმაურების მოსაწოდებლად."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ეს შეტყობინება დაწინაურდა. შეეხეთ გამოხმაურების მოსაწოდებლად."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ეს შეტყობინება ჩამოქვეითდა. შეეხეთ გამოხმაურების მოსაწოდებლად."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"გამოცადეთ გაფართოებული შეტყობინებები"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"შემოთავაზებული ქმედებების, პასუხების და სხვა მითითებების მიღების გასაგრძელებლად ჩართეთ გაფართოებული შეტყობინებები. Android-ის ადაპტაციური შეტყობინებები აღარაა მხარდაჭერილი."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ჩართვა"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ახლა არა"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"გაფართოებული შეტყობინებები"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"შემოთავაზებული მოქმედებები და პასუხები ამიერიდან უზრუნველყოფილია გაფართოებული შეტყობინებების მიერ. Android-ის ადაპტაციური შეტყობინებები აღარაა მხარდაჭერილი."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"კარგი"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"გამორთვა"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"შეიტყვეთ მეტი"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"გაფართოებულ შეტყობინებებს შეუძლია ყველა შეტყობინების კონტენტის, მათ შორის, ისეთი პერსონალური ინფორმაციის წაკითხვა, როგორიცაა კონტაქტების სახელები და შეტყობინებები. ამ ფუნქციას ასევე შეუძლია შეტყობინებების დახურვა ან შეტყობინებათა ღილაკების ამოქმედება, მაგალითად, სატელეფონო ზარებზე პასუხი.\n\nამ ფუნქციას ასევე შეუძლია პრიორიტეტული რეჟიმის ჩართვა თუ გამორთვა და დაკავშირებული პარამეტრების შეცვლა."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"გაფართოებულმა შეტყობინებებმა ჩაანაცვლა Android-ის ადაპტაციური შეტყობინებების ფუნქცია Android 12-ში. ეს ფუნქცია გაჩვენებთ შემოთავაზებულ მოქმედებებს და პასუხებს, ამასთანავე კი ახდენს თქვენი შეტყობინებების ორგანიზებას.\n\nგაფართოებულ შეტყობინებებს შეუძლია ყველა შეტყობინების კონტენტზე, მათ შორის, ისეთ პერსონალურ ინფორმაციაზე წვდომა, როგორიცაა კონტაქტების სახელები და შეტყობინებები. ამ ფუნქციას ასევე შეუძლია შეტყობინებათა დახურვა ან მათზე პასუხის გაცემა, მაგალითად, სატელეფონო ზარებზე პასუხი და „არ შემაწუხოთ“ რეჟიმის მართვა."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"რუტინის რეჟიმის საინფორმაციო შეტყობინება"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ბატარეა შეიძლება დაჯდეს დატენის ჩვეულ დრომდე"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ბატარეის დამზოგი გააქტიურდა ბატარეის მუშაობის გასახანგრძლივლებლად"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 4e10167..abddce1 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1707,7 +1707,7 @@
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Дайын"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Төте жолды өшіру"</string>
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Төте жолды пайдалану"</string>
- <string name="color_inversion_feature_name" msgid="326050048927789012">"Түстер инверсиясы"</string>
+ <string name="color_inversion_feature_name" msgid="326050048927789012">"Түс инверсиясы"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Түсті түзету"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Экранды қарайту"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Пайдаланушы дыбыс деңгейі пернелерін басып ұстап тұрды. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қосулы."</string>
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Монарх"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Кварто"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Белгісіз портреттік"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Белгісіз ландшафт"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Тоқтатылды"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Әкімші жаңартқан"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Әкімші жойған"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Жарайды"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Батареяны үнемдеу режимі қараңғы тақырыпты іске қосады және фондық әрекеттерге, кейбір визуалдық әсерлерге, \"Ok Google\" сияқты функцияларға шектеу қояды немесе оларды өшіреді.\n\n"<annotation id="url">"Толығырақ"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Батареяны үнемдеу режимі қараңғы тақырыпты іске қосады және фондық әрекеттерге, кейбір визуалдық әсерлерге, \"Ok Google\" сияқты функцияларға шектеу қояды немесе оларды өшіреді."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Батареяны үнемдеу режимі қараңғы тақырыпты іске қосады және фондық әрекеттерге, кейбір визуалдық әсерлер мен белгілі бір функцияларға шектеу қояды немесе оларды өшіреді.\n\n"<annotation id="url">"Толығырақ"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Батареяны үнемдеу режимі қараңғы тақырыпты іске қосады және фондық әрекеттерге, кейбір визуалдық әсерлер мен белгілі бір функцияларға шектеу қояды немесе оларды өшіреді."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Дерек шығынын азайту үшін Трафикті үнемдеу режимінде кейбір қолданбаларға деректі фондық режимде жіберуге және алуға тыйым салынады. Ашық тұрған қолданба деректі шектеулі шамада пайдаланады (мысалы, кескіндер оларды түрткенге дейін көрсетілмейді)."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Трафикті үнемдеу режимі қосылсын ба?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Қосу"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Бұл хабарландырудың маңыздылық деңгейі \"Үнсіз\" санатына төмендетілді. Пікір қалдыру үшін түртіңіз."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Бұл хабарландырудың маңыздылық деңгейі көтерілді. Пікір қалдыру үшін түртіңіз."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Бұл хабарландырудың маңыздылық деңгейі төмендетілді. Пікір қалдыру үшін түртіңіз."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Кеңейтілген хабарландыруларды пайдалану"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Ұсынылған әрекеттер, жауаптар және т.б. алып отыру үшін \"Кеңейтілген хабарландырулар\" функциясын қосыңыз. Android-тың \"Бейімделетін хабарландырулар\" функциясына бұдан былай қолдау көрсетілмейді."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Қосу"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Қазір емес"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Толығырақ"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"\"Кеңейтілген хабарландырулар\" функциясы барлық хабарландыру мазмұнын (контакт атаулары мен хабарлар сияқты жеке ақпаратты қоса алғанда) оқи алады. Сондай-ақ бұл функция арқылы хабарландыруларды жабуға немесе хабарландырулардағы түймелерді басқаруға (мысалы, телефон қоңырауларына жауап беру) болады.\n\nОл арқылы \"Маңызды\" режимін қосуға немесе өшіруге, қатысты параметрлерді өзгертуге де болады."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Режим туралы хабарландыру"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батарея заряды азаюы мүмкін"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Батарея ұзаққа жетуі үшін, Батареяны үнемдеу режимі іске қосылды"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 81dc891..4834695 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"ធំ"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"មិនស្គាល់បញ្ឈរ"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"មិនស្គាល់ទេសភាព"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"បានបោះបង់"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ធ្វើបច្ចុប្បន្នភាពដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"លុបដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"យល់ព្រម"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"មុខងារសន្សំថ្មបើករចនាប័ទ្មងងឹត និងបិទឬដាក់កំហិតលើសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលរូបភាពមួយចំនួន និងមុខងារដូចជា “Ok Google” ជាដើម\n\n"<annotation id="url">"ស្វែងយល់បន្ថែម"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"មុខងារសន្សំថ្មបើករចនាប័ទ្មងងឹត និងបិទឬដាក់កំហិតលើសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលរូបភាពមួយចំនួន និងមុខងារដូចជា “Ok Google” ជាដើម។"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"មុខងារសន្សំថ្មបើករចនាប័ទ្មងងឹត និងដាក់កំហិត ឬបិទសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលរូបភាពមួយចំនួន និងមុខងារជាក់លាក់។\n\n"<annotation id="url">"ស្វែងយល់បន្ថែម"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"មុខងារសន្សំថ្មបើករចនាប័ទ្មងងឹត និងដាក់កំហិត ឬបិទសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលរូបភាពមួយចំនួន និងមុខងារជាក់លាក់។"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ដើម្បីជួយកាត់បន្ថយការប្រើប្រាស់ទិន្នន័យ កម្មវិធីសន្សំសំចៃទិន្នន័យរារាំងកម្មវិធីមួយចំនួនមិនឲ្យបញ្ជូន ឬទទួលទិន្នន័យនៅផ្ទៃខាងក្រោយទេ។ កម្មវិធីដែលអ្នកកំពុងប្រើនាពេលបច្ចុប្បន្នអាចចូលប្រើប្រាស់ទិន្នន័យបាន ប៉ុន្តែអាចនឹងមិនញឹកញាប់ដូចមុនទេ។ ឧទាហរណ៍ រូបភាពមិនបង្ហាញទេ លុះត្រាតែអ្នកប៉ះរូបភាពទាំងនោះ។"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"បើកកម្មវិធីសន្សំសំចៃទិន្នន័យ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"បើក"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ការជូនដំណឹងនេះត្រូវបានបន្ទាបតំណែងទៅស្ងាត់។ សូមចុចដើម្បីផ្ដល់មតិកែលម្អ។"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ការជូនដំណឹងនេះត្រូវបានចាត់ថ្នាក់ខ្ពស់ជាងមុន។ សូមចុចដើម្បីផ្ដល់មតិកែលម្អ។"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ការជូនដំណឹងនេះត្រូវបានចាត់ថ្នាក់ទាបជាងមុន។ សូមចុចដើម្បីផ្ដល់មតិកែលម្អ។"</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"សាកល្បងប្រើការជូនដំណឹងប្រសើរជាងមុន"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"ដើម្បីបន្តទទួលបានការឆ្លើយតប សកម្មភាពដែលបានណែនាំ និងអ្វីៗជាច្រើនទៀត សូមបើកការជូនដំណឹងប្រសើរជាងមុន។ ការជូនដំណឺងដែលមានភាពបត់បែន Android មិនអាចប្រើបានទៀតទេ។"</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"បើក"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"កុំទាន់"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ស្វែងយល់បន្ថែម"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"ការជូនដំណឹងប្រសើរជាងមុនអាចអានខ្លឹមសារជូនដំណឹងទាំងអស់ រួមទាំងព័ត៌មានផ្ទាល់ខ្លួនដូចជា ឈ្មោះទំនាក់ទំនង និងសារជាដើម។ មុខងារនេះក៏អាចច្រានចោលការជូនដំណឹង ឬធ្វើសកម្មភាពលើប៊ូតុងនៅក្នុងការជូនដំណឹងផងដែរ ដូចជាការទទួលការហៅទូរសព្ទជាដើម។\n\nមុខងារនេះក៏អាចបើកឬបិទមុខងារអាទិភាព និងផ្លាស់ប្ដូរការកំណត់ដែលពាក់ព័ន្ធផងដែរ។"</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ការជូនដំណឹងព័ត៌មានរបស់មុខងារទម្លាប់"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ថ្មអាចនឹងអស់ មុនពេលសាកថ្មធម្មតា"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"បានបើកដំណើរការមុខងារសន្សំថ្ម ដើម្បីបង្កើនកម្រិតថាមពលថ្ម"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 02448bd..07e0ca3 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1773,6 +1773,28 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"ಮೊನಾರ್ಕ್"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"ಕ್ವಾರ್ಟೊ"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) -->
+ <skip />
+ <!-- no translation found for mediasize_na_ansi_d (254005964819282724) -->
+ <skip />
+ <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) -->
+ <skip />
+ <!-- no translation found for mediasize_na_ansi_f (146980362213260987) -->
+ <skip />
+ <!-- no translation found for mediasize_na_arch_a (5280681822380032361) -->
+ <skip />
+ <!-- no translation found for mediasize_na_arch_b (2113344093437297427) -->
+ <skip />
+ <!-- no translation found for mediasize_na_arch_c (971002546186856623) -->
+ <skip />
+ <!-- no translation found for mediasize_na_arch_d (6450996075335049806) -->
+ <skip />
+ <!-- no translation found for mediasize_na_arch_e (6782708486949266519) -->
+ <skip />
+ <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) -->
+ <skip />
+ <!-- no translation found for mediasize_na_super_b (6964127155618393178) -->
+ <skip />
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1831,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"ಅಪರಿಚಿತ ಪೋರ್ಟ್ರೇಟ್"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"ಅಪರಿಚಿತ ಲ್ಯಾಂಡ್ಸ್ಕೇಪ್"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ರದ್ದುಮಾಡಲಾಗಿದೆ"</string>
@@ -1852,8 +1875,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಅಪ್ಡೇಟ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಅಳಿಸಿದ್ದಾರೆ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ಸರಿ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್ಗಳು ಮತ್ತು “Ok Google” ನಂತಹ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ ಅಥವಾ ಆಫ್ ಮಾಡುತ್ತದೆ.\n\n"<annotation id="url">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್ಗಳು ಮತ್ತು “Ok Google” ನಂತಹ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ ಅಥವಾ ಆಫ್ ಮಾಡುತ್ತದೆ."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್ಗಳು, ಮತ್ತು ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ ಅಥವಾ ಆಫ್ ಮಾಡುತ್ತದೆ.\n\n"<annotation id="url">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್ಗಳು, ಮತ್ತು ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ ಅಥವಾ ಆಫ್ ಮಾಡುತ್ತದೆ."</string>
<string name="data_saver_description" msgid="4995164271550590517">"ಡೇಟಾ ಬಳಕೆ ಕಡಿಮೆ ಮಾಡುವ ನಿಟ್ಟಿನಲ್ಲಿ, ಡೇಟಾ ಸೇವರ್ ಕೆಲವು ಅಪ್ಲಿಕೇಶನ್ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಡೇಟಾ ಕಳುಹಿಸುವುದನ್ನು ಅಥವಾ ಸ್ವೀಕರಿಸುವುದನ್ನು ತಡೆಯುತ್ತದೆ. ನೀವು ಪ್ರಸ್ತುತ ಬಳಸುತ್ತಿರುವ ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು ಆದರೆ ಪದೇ ಪದೇ ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಇದರರ್ಥ, ಉದಾಹರಣೆಗೆ, ನೀವು ಅವುಗಳನ್ನು ಟ್ಯಾಪ್ ಮಾಡುವವರೆಗೆ ಆ ಚಿತ್ರಗಳು ಕಾಣಿಸಿಕೊಳ್ಳುವುದಿಲ್ಲ."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ಡೇಟಾ ಸೇವರ್ ಆನ್ ಮಾಡಬೇಕೇ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ಆನ್ ಮಾಡಿ"</string>
@@ -2073,12 +2096,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ಈ ಅಧಿಸೂಚನೆಗೆ ಸೈಲೆಂಟ್ಗೆ ಹಿಂಬಡ್ತಿ ನೀಡಲಾಗಿದೆ. ಪ್ರತಿಕ್ರಿಯೆ ನೀಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ಈ ಅಧಿಸೂಚನೆಗೆ ಮೇಲಿನ ಸ್ಥಾನವನ್ನು ನೀಡಲಾಗಿದೆ. ಪ್ರತಿಕ್ರಿಯೆ ನೀಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ಈ ಅಧಿಸೂಚನೆಗೆ ಕೆಳಗಿನ ಸ್ಥಾನವನ್ನು ನೀಡಲಾಗಿದೆ. ಪ್ರತಿಕ್ರಿಯೆ ನೀಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"ವರ್ಧಿತ ಅಧಿಸೂಚನೆಗಳು ಪ್ರಯತ್ನಿಸಿ"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"ಸೂಚಿಸಲಾದ ಕ್ರಿಯೆಗಳು, ಪ್ರತ್ಯುತ್ತರಗಳು ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ಪಡೆಯಲು, ವರ್ಧಿತ ಅಧಿಸೂಚನೆಗಳನ್ನು ಆನ್ ಮಾಡಿ. Android ಅಡಾಪ್ಟಿವ್ ಅಧಿಸೂಚನೆಗಳು ಇನ್ನು ಮುಂದೆ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ಆನ್ ಮಾಡಿ"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ಈಗ ಬೇಡ"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"ವರ್ಧಿತ ಅಧಿಸೂಚನೆಗಳು ಸಂಪರ್ಕ ಹೆಸರುಗಳು ಮತ್ತು ಸಂದೇಶಗಳಂತಹ ವೈಯಕ್ತಿಕ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಂತೆ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆ ವಿಷಯವನ್ನು ಓದಬಹುದು. ಈ ವೈಶಿಷ್ಟ್ಯವು ಅಧಿಸೂಚನೆಗಳನ್ನು ವಜಾಗೊಳಿಸಬಹುದು ಅಥವಾ ಫೋನ್ ಕರೆಗಳಿಗೆ ಉತ್ತರಿಸುವಂತಹ ಅಧಿಸೂಚನೆಗಳಲ್ಲಿನ ಬಟನ್ಗಳಿಗೆ ಸಂಬಂಧಿಸಿದ ಕ್ರಮ ತೆಗೆದುಕೊಳ್ಳಬಹುದು.\n\nಈ ವೈಶಿಷ್ಟ್ಯವು ಆದ್ಯತಾ ಮೋಡ್ ಅನ್ನು ಆನ್ ಅಥವಾ ಆಫ್ ಮಾಡಬಹುದು ಮತ್ತು ಸಂಬಂಧಿತ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬದಲಾಯಿಸಬಹುದು."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ದೈನಂದಿನ ಸ್ಥಿತಿಯ ಮಾಹಿತಿಯ ಅಧಿಸೂಚನೆ"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ಚಾರ್ಜ್ಗೆ ಮೊದಲೆ ಬ್ಯಾಟರಿ ಮುಗಿದು ಬಿಡಬಹುದು"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ಬ್ಯಾಟರಿ ಅವಧಿ ಹೆಚ್ಚಿಸಲು ಬ್ಯಾಟರಿ ಸೇವರ್ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index da8f4ab..8208182 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"모나크"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"쿼토"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"풀스캡"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"지정되지 않은 세로 방향"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"지정되지 않은 가로 방향"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"취소됨"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"관리자에 의해 업데이트되었습니다."</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"관리자에 의해 삭제되었습니다."</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"확인"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"절전 기능은 어두운 테마를 사용 설정하고 백그라운드 활동, 일부 시각 효과, \'Hey Google\'과 같은 기능을 제한하거나 사용 중지합니다.\n\n"<annotation id="url">"자세히 알아보기"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"절전 기능은 어두운 테마를 사용 설정하고 백그라운드 활동, 일부 시각 효과, \'Hey Google\'과 같은 기능을 제한하거나 사용 중지합니다."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"절전 모드는 어두운 테마를 사용 설정하고 백그라운드 활동, 일부 시각 효과, 특정 기능을 제한하거나 사용 중지합니다.\n\n"<annotation id="url">"자세히 알아보기"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"절전 모드는 어두운 테마를 사용 설정하고 백그라운드 활동, 일부 시각 효과, 특정 기능을 제한하거나 사용 중지합니다."</string>
<string name="data_saver_description" msgid="4995164271550590517">"데이터 사용량을 줄이기 위해 데이터 절약 모드는 일부 앱이 백그라운드에서 데이터를 전송하거나 수신하지 못하도록 합니다. 현재 사용 중인 앱에서 데이터에 액세스할 수 있지만 빈도가 줄어듭니다. 예를 들면, 이미지를 탭하기 전에는 이미지가 표시되지 않습니다."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"데이터 절약 모드를 사용 설정하시겠습니까?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"사용 설정"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"이 알림의 중요도가 무음으로 하향되었습니다. 의견을 보내려면 탭하세요."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"이전에 이 알림의 중요도는 더 높았습니다. 의견을 보내려면 탭하세요."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"이전에 이 알림의 중요도는 더 낮았습니다. 의견을 보내려면 탭하세요."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"개선된 알림 기능 사용해 보기"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"추천 작업, 답장 등을 계속 받으려면 개선된 알림 기능을 사용 설정하세요. Android 적응형 알림은 더 이상 지원되지 않습니다."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"사용 설정"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"나중에"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"자세히 알아보기"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"개선된 알림 기능은 연락처 이름과 메시지 등 개인 정보가 포함된 모든 알림 내용을 읽어줍니다. 알림을 닫거나 알림에 표시되는 버튼 관련 작업(예: 전화 받기)을 실행할 수도 있습니다.\n\n또한 이 기능은 우선순위 모드를 사용 또는 사용 중지하고 관련 설정을 변경할 수 있습니다."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"루틴 모드 정보 알림"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"평소에 충전하는 시간 전에 배터리가 소진될 수 있습니다."</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"배터리 수명을 연장하기 위해 절전 모드가 활성화되었습니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 8feb675..697b60b5 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch (184mm x 267mm)"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto (203mm x 254mm)"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap (203mm x 330mm)"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K (270mm x 390mm)"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K (195mm x 270mm)"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1 (102mm x 165mm)"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu (240mm x 322.1mm)"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2 (240mm x 332mm)"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4 (105mm x 235mm)"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"Ч"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Белгисиз, тикесинен"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Белгисиз, туурасынан"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Токтотулду"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Администраторуңуз жаңыртып койгон"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Администраторуңуз жок кылып салган"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ЖАРАЙТ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Батареяны үнөмдөгүч режиминде Караңгы тема күйгүзүлүп, фондогу аракеттер, айрым визуалдык эффекттер жана \"Окей, Google\" сыяктуу функциялар чектелип же өчүрүлөт\n\n"<annotation id="url">"Кеңири маалымат"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Батареяны үнөмдөгүч режиминде Караңгы тема күйгүзүлүп, фондогу аракеттер, айрым визуалдык эффекттер жана \"Окей, Google\" сыяктуу функциялар чектелип же өчүрүлөт."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Батареяны үнөмдөгүч режиминде Караңгы тема күйгүзүлүп, фондогу аракеттер, айрым визуалдык эффекттер жана белгилүү бир функциялар чектелип же өчүрүлөт.\n\n"<annotation id="url">"Кеңири маалымат"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Батареяны үнөмдөгүч режиминде Караңгы тема күйгүзүлүп, фондогу аракеттер, айрым визуалдык эффекттер жана белгилүү бир функциялар чектелип же өчүрүлөт."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Трафикти үнөмдөө режиминде айрым колдонмолор маалыматтарды фондо өткөрө алышпайт. Учурда сиз пайдаланып жаткан колдонмо маалыматтарды жөнөтүп/ала алат, бирок адаттагыдан азыраак өткөргөндүктөн, анын айрым функциялары талаптагыдай иштебей коюшу мүмкүн. Мисалы, сүрөттөр басылмайынча жүктөлбөйт."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Трафикти үнөмдөө режимин иштетесизби?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Күйгүзүү"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Бул билдирменин маанилүүлүгү Үнсүз болуп төмөндөтүлдү. Пикир билдирүү үчүн таптап коюңуз."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Бул билдирменин маанилүүлүгү жогорулатылды. Пикир билдирүү үчүн таптап коюңуз."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Бул билдирменин маанилүүлүгү төмөндөтүлдү. Пикир билдирүү үчүн таптап коюңуз."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Жакшыр-ган бил-ди байкап көрүү"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Сунушталган аракеттерди, жоопторду жана башка маалыматты ала берүү үчүн жакшыртылган билдирмелерди күйгүзүңүз. Android\'дин Ыңгайлаштырылуучу билдирмелери колдоого алынбай калды."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Күйгүзүү"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Азыр эмес"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Кененирээк"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Жакшыртылган билдирмелер бардык билдирмелердин мазмунун, ошондой эле байланыштардын аты-жөнү жана билдирүүлөр сыяктуу жеке маалыматты окуй алат. Мындан тышкары, билдирмелерди жаап же телефон чалууларына жооп берүү сыяктуу билдирмелердеги баскычтарды баса алат.\n\nБул функция Маанилүү жазышуулар режимин күйгүзүп же өчүрүп, ошондой эле анын жөндөөлөрүн өзгөртө алат."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Режимдин адаттагы билдирмеси"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батарея кубаттоого чейин отуруп калышы мүмкүн"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Батареянын отуруп калбашы үчүн Батареяны үнөмдөгүч режими иштетилди"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index caa9154..f75612f 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Unknown portrait"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Unknown landscape"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ຍົກເລີກແລ້ວ"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ຖືກອັບໂຫລດໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ຖືກລຶບອອກໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ຕົກລົງ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"ຕົວປະຢັດແບັດເຕີຣີຈະເປີດໃຊ້ຮູບແບບສີສັນມືດ ແລະ ຈຳກັດ ຫຼື ປິດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກດ້ານພາບບາງຢ່າງ ແລະ ຄຸນສົມບັດຕ່າງໆ ເຊັ່ນ: “Ok Google”\n\n"<annotation id="url">"ສຶກສາເພີ່ມເຕີມ"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"ຕົວປະຢັດແບັດເຕີຣີຈະເປີດໃຊ້ຮູບແບບສີສັນມືດ ແລະ ຈຳກັດ ຫຼື ປິດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກດ້ານພາບບາງຢ່າງ ແລະ ຄຸນສົມບັດຕ່າງໆ ເຊັ່ນ: “Ok Google”."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"ຕົວປະຢັດແບັດເຕີຣີຈະເປີດໃຊ້ຮູບແບບສີສັນມືດ ແລະ ຈຳກັດ ຫຼື ປິດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກທາງພາບຈຳນວນໜຶ່ງ ແລະ ຄຸນສົມບັດບາງຢ່າງ.\n\n"<annotation id="url">"ສຶກສາເພີ່ມເຕີມ"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"ຕົວປະຢັດແບັດເຕີຣີຈະເປີດໃຊ້ຮູບແບບສີສັນມືດ ແລະ ຈຳກັດ ຫຼື ປິດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກທາງພາບຈຳນວນໜຶ່ງ ແລະ ຄຸນສົມບັດບາງຢ່າງ."</string>
<string name="data_saver_description" msgid="4995164271550590517">"ເພື່ອຊ່ວຍຫຼຸດຜ່ອນການນຳໃຊ້ຂໍ້ມູນ, ຕົວປະຢັດອິນເຕີເນັດຈະປ້ອງກັນບໍ່ໃຫ້ບາງແອັບສົ່ງ ຫຼື ຮັບຂໍ້ມູນໃນພື້ນຫຼັງ. ແອັບໃດໜຶ່ງທີ່ທ່ານກຳລັງໃຊ້ຢູ່ຈະສາມາດເຂົ້າເຖິງຂໍ້ມູນໄດ້ ແຕ່ອາດເຂົ້າເຖິງໄດ້ຖີ່ໜ້ອຍລົງ. ນີ້ອາດໝາຍຄວາມວ່າ ຮູບພາບຕ່າງໆອາດບໍ່ສະແດງຈົນກວ່າທ່ານຈະແຕະໃສ່ກ່ອນ."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ເປີດຕົວປະຢັດອິນເຕີເນັດບໍ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ເປີດໃຊ້"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ການແຈ້ງເຕືອນນີ້ຖືກຫຼຸດລະດັບເປັນປິດສຽງແລ້ວ. ແຕະເພື່ອສົ່ງຄຳຕິຊົມ."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ການແຈ້ງເຕືອນນີ້ຖືກເລື່ອນລະດັບຂຶ້ນແລ້ວ. ແຕະເພື່ອສົ່ງຄຳຕິຊົມ."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ການແຈ້ງເຕືອນນີ້ຖືກຫຼຸດລະດັບລົງແລ້ວ. ແຕະເພື່ອສົ່ງຄຳຕິຊົມ."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"ລອງໃຊ້ການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນ"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"ກະລຸນາເປີດໃຊ້ການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນເພື່ອສືບຕໍ່ຮັບຄຳສັ່ງທີ່ແນະນຳ, ການຕອບກັບ ແລະ ອື່ນໆ. ບໍ່ຮອງຮັບການແຈ້ງເຕືອນແບບປັບຕົວໄດ້ຂອງ Android ອີກຕໍ່ໄປແລ້ວ."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ເປີດໃຊ້"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ບໍ່ຟ້າວເທື່ອ"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"ການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນ"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"ຕອນນີ້ຄຳສັ່ງ ແລະ ການຕອບກັບທີ່ແນະນຳແມ່ນສະໜອງໃຫ້ໂດຍການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນ. ບໍ່ຮອງຮັບການແຈ້ງເຕືອນແບບປັບຕົວໄດ້ຂອງ Android ອີກຕໍ່ໄປແລ້ວ."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ຕົກລົງ"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ປິດໄວ້"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ສຶກສາເພີ່ມເຕີມ"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"ການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນສາມາດອ່ານເນື້ອຫາການແຈ້ງເຕືອນທັງໝົດໄດ້, ຮວມທັງຂໍ້ມູນສ່ວນຕົວ ເຊັ່ນ: ຊື່ຜູ້ຕິດຕໍ່ ແລະ ຂໍ້ຄວາມຕ່າງໆ. ນອກຈາກນັ້ນ, ຄຸນສົມບັດນີ້ຍັງສາມາດປິດການແຈ້ງເຕືອນໄວ້ ຫຼື ໃຊ້ຄຳສັ່ງຕ່າງໆຢູ່ປຸ່ມໃນການແຈ້ງເຕືອນໄດ້ນຳ ເຊັ່ນ: ການຮັບສາຍໂທລະສັບ.\n\nຄຸນສົມບັດນີ້ສາມາດເປີດ ຫຼື ປິດໂໝດສຳຄັນ ແລະ ປ່ຽນການຕັ້ງຄ່າທີ່ກ່ຽວຂ້ອງໄດ້ນຳ."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"ການແຈ້ງເຕືອນແບບປັບຕົວໄດ້ຂອງ Android ຖືກແທນທີ່ດ້ວຍການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນໃນ Android 12 ແລ້ວ. ຄຸນສົມບັດນີ້ສະແດງຄຳສັ່ງ ແລະ ການຕອບກັບທີ່ແນະນຳ ແລະ ຈັດລະບຽບການແຈ້ງເຕືອນຂອງທ່ານ.\n\nການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນສາມາດເຂົ້າເຖິງເນື້ອຫາການແຈ້ງເຕືອນໄດ້, ຮວມທັງຂໍ້ມູນສ່ວນຕົວ ເຊັ່ນ: ຊື່ຜູ້ຕິດຕໍ່ ແລະ ຂໍ້ຄວາມ. ຄຸນສົມບັດນີ້ສາມາດປິດ ຫຼື ຕອບກັບຫາການແຈ້ງເຕືອນໄດ້ນຳ ເຊັ່ນ: ການຮັບສາຍໂທລະສັບ ແລະ ການຄວບຄຸມໂໝດຫ້າມລົບກວນ."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ການແຈ້ງເຕືອນຂໍ້ມູນໂໝດກິດຈະວັດປະຈຳວັນ"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ແບັດເຕີຣີອາດໝົດກ່ອນການສາກຕາມປົກກະຕິ"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ເປີດຕົວປະຢັດແບັດເຕີຣີເພື່ອຂະຫຍາຍອາຍຸແບັດເຕີຣີ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index ed4f15e..88c90b7 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1817,6 +1817,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1853,6 +1864,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Nežinomas stačias"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Nežinomas gulsčias"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Atšaukta"</string>
@@ -1898,8 +1910,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atnaujino administratorius"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Ištrynė administratorius"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Gerai"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Akumuliatoriaus tausojimo priemonė įjungia tamsiąją temą ir apriboja arba išjungia veiklą fone, kai kuriuos vizualinius efektus ir funkcijas, pvz., „Ok Google“\n\n"<annotation id="url">"Sužinokite daugiau"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Akumuliatoriaus tausojimo priemonė įjungia tamsiąją temą ir apriboja arba išjungia veiklą fone, kai kuriuos vizualinius efektus ir funkcijas, pvz., „Ok Google“."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Akumuliatoriaus tausojimo priemonė įjungia tamsiąją temą ir apriboja arba išjungia veiklą fone, kai kuriuos vaizdinius efektus bei tam tikras funkcijas.\n\n"<annotation id="url">"Sužinokite daugiau"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Akumuliatoriaus tausojimo priemonė įjungia tamsiąją temą ir apriboja arba išjungia veiklą fone, kai kuriuos vaizdinius efektus bei tam tikras funkcijas."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Kad padėtų sumažinti duomenų naudojimą, Duomenų taupymo priemonė neleidžia kai kurioms programoms siųsti ar gauti duomenų fone. Šiuo metu naudojama programa gali pasiekti duomenis, bet tai bus daroma rečiau. Tai gali reikšti, kad, pvz., vaizdai nebus pateikiami, jei jų nepaliesite."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Įj. Duomenų taupymo priemonę?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Įjungti"</string>
@@ -2139,12 +2151,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Šio pranešimo svarba sumažinta iki begarsio lygio. Palieskite, kad pateiktumėte atsiliepimą."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Šio pranešimo svarba padidinta. Palieskite, kad pateiktumėte atsiliepimą."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Šio pranešimo svarba sumažinta. Palieskite, kad pateiktumėte atsiliepimą."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Išb. patobulintus pranešimus"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Norėdami toliau gauti siūlomus veiksmus, atsakymus ir daugiau, įjunkite patobulintus pranešimus. „Android“ prisitaikantys pranešimai nebepalaikomi."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Įjungti"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ne dabar"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Sužinokite daugiau"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Patobulintų pranešimų funkcija gali skaityti visų pranešimų turinį, įskaitant asmens informaciją (pvz., kontaktų vardus ir pranešimus). Ši funkcija taip pat gali atsisakyti pranešimų ar imtis veiksmų su pranešimuose esančiais mygtukais, pvz., atsakyti į telefono skambučius.\n\nBe to, ši funkcija gali įjungti arba išjungti svarbiausių pokalbių režimą ir pakeisti susijusius nustatymus."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Veiksmų sekos režimo informacijos pranešimas"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akumuliatoriaus energija gali išsekti prieš įprastą įkrovimą"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Akumuliatoriaus tausojimo priemonė suaktyvinta, kad akumuliatorius veiktų ilgiau"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 94a50ea..c952dc2 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1795,6 +1795,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1831,6 +1842,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Nezināma izmēra portrets"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Nezināma izmēra ainava"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Atcelts"</string>
@@ -1875,8 +1887,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atjaunināja administrators"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Dzēsa administrators"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Labi"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Akumulatora enerģijas taupīšanas režīmā tiek ieslēgts tumšais motīvs un ierobežotas vai izslēgtas darbības fonā, konkrēti vizuālie efekti un tādas funkcijas kā īsinājumvārda “Hey Google” atpazīšana.\n\n"<annotation id="url">"Uzzināt vairāk"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Akumulatora enerģijas taupīšanas režīmā tiek ieslēgts tumšais motīvs un ierobežotas vai izslēgtas darbības fonā, konkrēti vizuālie efekti un tādas funkcijas kā īsinājumvārda “Hey Google” atpazīšana."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Akumulatora enerģijas taupīšanas režīmā tiek ieslēgts tumšais motīvs, kā arī tiek ierobežotas vai izslēgtas darbības fonā, daži vizuālie efekti un funkcijas.\n\n"<annotation id="url">"Uzzināt vairāk"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Akumulatora enerģijas taupīšanas režīmā tiek ieslēgts tumšais motīvs, kā arī tiek ierobežotas vai izslēgtas darbības fonā, daži vizuālie efekti un funkcijas."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Lai samazinātu datu lietojumu, datu lietojuma samazinātājs neļauj dažām lietotnēm fonā nosūtīt vai saņemt datus. Lietotne, kuru pašlaik izmantojat, var piekļūt datiem, bet, iespējams, piekļūs tiem retāk (piemēram, attēli tiks parādīti tikai tad, kad tiem pieskarsieties)."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vai ieslēgt datu lietojuma samazinātāju?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ieslēgt"</string>
@@ -2106,12 +2118,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Šī paziņojuma svarīgums tika pazemināts, un paziņojums tiks rādīts bez skaņas. Lai sniegtu atsauksmes, pieskarieties."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Šī paziņojuma rangs tika paaugstināts. Lai sniegtu atsauksmes, pieskarieties."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Šī paziņojuma rangs tika pazemināts. Lai sniegtu atsauksmes, pieskarieties."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Uzlabotie paziņojumi"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Lai arī turpmāk saņemtu darbību un atbilžu ieteikumus un citu saturu, ieslēdziet uzlabotos paziņojumus. Android adaptīvie paziņojumi vairs netiek atbalstīti."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Ieslēgt"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Vēlāk"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Uzzināt vairāk"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Funkcija “Uzlabotie paziņojumi” var lasīt visu paziņojumu saturu, tostarp personas informāciju, piemēram, kontaktpersonu vārdus un ziņojumus. Šī funkcija var arī noraidīt paziņojumus un izmantot paziņojumos esošās pogas darbību veikšanai, piemēram, atbildēt uz tālruņa zvaniem.\n\nTurklāt šī funkcija var ieslēgt un izslēgt režīmu Prioritāte un mainīt ar to saistītos iestatījumus."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Informatīvs paziņojums par akumulatoru"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akumulators var izlādēties pirms parastā uzlādes laika"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Aktivizēts akumulatora enerģijas taupīšanas režīms, lai palielinātu akumulatora darbības ilgumu"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 5e90faa..82ac5828 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1566,7 +1566,7 @@
<string name="action_menu_overflow_description" msgid="4579536843510088170">"Повеќе опции"</string>
<string name="action_bar_home_description_format" msgid="5087107531331621803">"%1$s, %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
- <string name="storage_internal" msgid="8490227947584914460">"Внатрешно заедничко место за складирање"</string>
+ <string name="storage_internal" msgid="8490227947584914460">"Внатрешен споделен капацитет"</string>
<string name="storage_sd_card" msgid="3404740277075331881">"СД картичка"</string>
<string name="storage_sd_card_label" msgid="7526153141147470509">"<xliff:g id="MANUFACTURER">%s</xliff:g> СД-картичка"</string>
<string name="storage_usb_drive" msgid="448030813201444573">"USB-меморија"</string>
@@ -1621,7 +1621,7 @@
<string name="wireless_display_route_description" msgid="8297563323032966831">"Безжичен приказ"</string>
<string name="media_route_button_content_description" msgid="2299223698196869956">"Емитувај"</string>
<string name="media_route_chooser_title" msgid="6646594924991269208">"Поврзи се со уред"</string>
- <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Префрли екран на уред"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Емитување екран на уред"</string>
<string name="media_route_chooser_searching" msgid="6119673534251329535">"Се бараат уреди..."</string>
<string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Поставки"</string>
<string name="media_route_controller_disconnect" msgid="7362617572732576959">"Прекини врска"</string>
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Монарх"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Кварто"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Непознат портрет"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Непознат пејзаж"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Откажано"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирано од администраторот"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Избришано од администраторот"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Во ред"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"„Штедачот на батерија“ вклучува темна тема и исклучува или ограничува активност во заднина, некои визуелни ефекти и функции како „Ok Google“\n\n"<annotation id="url">"Дознајте повеќе"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"„Штедачот на батерија“ вклучува темна тема и исклучува или ограничува активност во заднина, некои визуелни ефекти и функции како „Ok Google“."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"„Штедачот на батерија“ ја вклучува темната тема и ги ограничува или исклучува активноста во заднина, некои визуелни ефекти и одредени функции.\n\n"<annotation id="url">"Дознајте повеќе"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"„Штедачот на батерија“ ја вклучува темната тема и ги ограничува или исклучува активноста во заднина, некои визуелни ефекти и одредени функции."</string>
<string name="data_saver_description" msgid="4995164271550590517">"За да се намали користењето интернет, „Штедачот на интернет“ спречува дел од апликациите да испраќаат или да примаат податоци во заднина. Одредена апликација што ја користите ќе може да користи интернет, но можеби тоа ќе го прави поретко. Ова значи, на пример, дека сликите нема да се прикажуваат додека не ги допрете."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Да се вклучи „Штедач на интернет“?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Вклучи"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Приоритетноста на известувањево е намалена на „Тивко“. Допрете за да дадете повратни информации."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Известувањево е рангирано повисоко. Допрете за да дадете повратни информации."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Известувањево е рангирано пониско. Допрете за да дадете повратни информации."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Пробај „Подобрени известувања“"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Вклучете ги „Подобрените известувања“ за да продолжите да добивате предлози за дејства, одговори и слично. „Приспособливите известувања на Android“ веќе не се достапни."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Вклучи"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Не сега"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Подобрени известувања"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"„Подобрените известувања“ сега ги даваат предложените дејства и одговорите. „Приспособливите известувања на Android“ веќе не се достапни."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Во ред"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Исклучи"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Дознајте повеќе"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"„Подобрените известувања“ може да ги читаат сите содржини од известувањата, вклучително и личните податоци, како што се имињата на контактите и пораките. Функцијава ќе може и да отфрла известувања или да ги користи копчињата во известувањата, како на пр., да одговара на телефонски повици.\n\nФункцијава може и да го вклучува или исклучува „Приоритетниот режим“ и да ги менува поврзаните поставки."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"„Подобрените известувања“ ги заменија „Приспособливите известувања на Android“ во Android 12. Оваа функција прикажува предложени дејства и одговори и ги организира вашите известувања.\n\n„Подобрените известувања“ може да пристапат до содржините од известувањата, вклучително и личните податоци, како што се имињата на контактите и пораките. Функцијава може и да отфрла или одговара на известувања, како на пример, одговарање телефонски повици и контролирање на „Не вознемирувај“."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Известување за информации за режимот за рутини"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батеријата може да се потроши пред вообичаеното време за полнење"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Активиран е „Штедачот на батерија“ за да се продолжи траењето на батеријата"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 5a47e60..e6ff7ea 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"മൊണാർക്ക്"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"ക്വാർട്ടോ"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"ഫൂൾസ്കെയ്പ്പ്"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"കഹു"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"അജ്ഞാത പോർട്രെയ്റ്റ്"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"അജ്ഞാത ലാൻഡ്സ്കെയ്പ്പ്"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"റദ്ദാക്കി"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"നിങ്ങളുടെ അഡ്മിൻ അപ്ഡേറ്റ് ചെയ്യുന്നത്"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"നിങ്ങളുടെ അഡ്മിൻ ഇല്ലാതാക്കുന്നത്"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ശരി"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"ബാറ്ററി ലാഭിക്കൽ, ഡാർക്ക് തീം ഓണാക്കുന്നു, പശ്ചാത്തല പ്രവർത്തനവും ചില വിഷ്വൽ ഇഫക്റ്റുകളും “Ok Google” പോലുള്ള ഫീച്ചറുകളും നിയന്ത്രിക്കുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു\n\n"<annotation id="url">"കൂടുതലറിയുക"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"ബാറ്ററി ലാഭിക്കൽ, ഡാർക്ക് തീം ഓണാക്കുന്നു, പശ്ചാത്തല പ്രവർത്തനവും ചില വിഷ്വൽ ഇഫക്റ്റുകളും “Ok Google” പോലുള്ള ഫീച്ചറുകളും നിയന്ത്രിക്കുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"ബാറ്ററി ലാഭിക്കൽ ഡാർക്ക് തീം ഓണാക്കുന്നു, കൂടാതെ പശ്ചാത്തല ആക്റ്റിവിറ്റി, ചില വിഷ്വൽ ഇഫക്റ്റുകൾ, ചില ഫീച്ചറുകൾ എന്നിവ പരിമിതപ്പെടുത്തുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു.\n\n"<annotation id="url">"കൂടുതലറിയുക"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"ബാറ്ററി ലാഭിക്കൽ ഡാർക്ക് തീം ഓണാക്കുന്നു, കൂടാതെ പശ്ചാത്തല ആക്റ്റിവിറ്റി, ചില വിഷ്വൽ ഇഫക്റ്റുകൾ, ചില ഫീച്ചറുകൾ എന്നിവ പരിമിതപ്പെടുത്തുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു."</string>
<string name="data_saver_description" msgid="4995164271550590517">"ഡാറ്റാ ഉപയോഗം കുറയ്ക്കാൻ സഹായിക്കുന്നതിനായി പശ്ചാത്തലത്തിൽ ഡാറ്റ അയയ്ക്കുകയോ സ്വീകരിക്കുകയോ ചെയ്യുന്നതിൽ നിന്ന് ചില ആപ്പുകളെ ഡാറ്റാ സേവർ തടയുന്നു. നിങ്ങൾ നിലവിൽ ഉപയോഗിക്കുന്ന ഒരു ആപ്പിന് ഡാറ്റ ആക്സസ് ചെയ്യാനാകും, എന്നാൽ വല്ലപ്പോഴും മാത്രമെ സംഭവിക്കുന്നുള്ളു. ഇതിനർത്ഥം, ഉദാഹരണമായി നിങ്ങൾ ടാപ്പ് ചെയ്യുന്നത് വരെ ചിത്രങ്ങൾ പ്രദർശിപ്പിക്കുകയില്ല എന്നാണ്."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ഡാറ്റ സേവർ ഓണാക്കണോ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ഓണാക്കുക"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ഈ അറിയിപ്പിനെ നിശബ്ദമാക്കി തരം താഴ്ത്തി. ഫീഡ്ബാക്ക് നൽകാൻ ടാപ്പ് ചെയ്യുക."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ഈ അറിയിപ്പിന് ഉയർന്ന റാങ്ക് നൽകി. ഫീഡ്ബാക്ക് നൽകാൻ ടാപ്പ് ചെയ്യുക."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ഈ അറിയിപ്പിന് താഴ്ന്ന റാങ്ക് നൽകി. ഫീഡ്ബാക്ക് നൽകാൻ ടാപ്പ് ചെയ്യുക."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"മെച്ചപ്പെടുത്തിയ അറിയിപ്പുകൾ പരീക്ഷിക്കൂ"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"നിർദ്ദേശിച്ച പ്രവർത്തനങ്ങളും മറുപടികളും മറ്റും ലഭിക്കുന്നത് തുടരാൻ, മെച്ചപ്പെടുത്തിയ അറിയിപ്പുകൾ ഓണാക്കുക. Android അഡാപ്റ്റീവ് അറിയിപ്പുകൾക്ക് ഇനി പിന്തുണയില്ല."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ഓണാക്കുക"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ഇപ്പോൾ വേണ്ട"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"കൂടുതലറിയുക"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"മെച്ചപ്പെടുത്തിയ അറിയിപ്പുകൾക്ക്, കോൺടാക്റ്റ് പേരുകളും സന്ദേശങ്ങളും പോലുള്ള വ്യക്തിപരമായ വിവരങ്ങൾ ഉൾപ്പെടെ എല്ലാ അറിയിപ്പ് ഉള്ളടക്കവും വായിക്കാനാകും. അറിയിപ്പുകൾ ഡിസ്മിസ് ചെയ്യാനോ ഫോൺ കോളുകൾക്ക് മറുപടി നൽകുന്നത് പോലെ അറിയിപ്പുകളിലെ ബട്ടണുകളിൽ നടപടിയെടുക്കാനോ ഈ ഫീച്ചറിന് കഴിയും.\n\nമുൻഗണനാ മോഡ് ഓണാക്കാനോ ഓഫാക്കാനോ ബന്ധപ്പെട്ട ക്രമീകരണം മാറ്റാനോ ഈ ഫീച്ചറിന് കഴിയും."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ദിനചര്യ മോഡ് വിവരത്തെ കുറിച്ചുള്ള അറിയിപ്പ്"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"സാധാരണയുള്ളതിലും നേരത്തെ ബാറ്ററിയുടെ ചാർജ് തീർന്നേക്കാം"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ബാറ്ററി ലൈഫ് വര്ദ്ധിപ്പിക്കാൻ, ബാറ്ററി ലാഭിക്കൽ സജീവമാക്കി"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 30ab692..5064068 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"Том"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Тодорхойгүй босоо цаас"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Тодорхойгүй хөндлөн цаас"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Цуцлагдсан"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Таны админ шинэчилсэн"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Таны админ устгасан"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Батарей хэмнэгч нь Бараан загварыг асааж, дэвсгэрийн үйл ажиллагаа, зарим визуал эффект болон “Hey Google” зэрэг онцлогуудыг хязгаарлаж эсвэл унтраана\n\n"<annotation id="url">"Нэмэлт мэдээлэл авах"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Батарей хэмнэгч нь Бараан загварыг асааж, дэвсгэрийн үйл ажиллагаа, зарим визуал эффект болон “Hey Google” зэрэг онцлогуудыг хязгаарлаж эсвэл унтраана."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Батарей хэмнэгч нь Бараан загварыг асааж, дэвсгэрийн үйл ажиллагаа, зарим визуал эффект болон тодорхой онцлогуудийг хязгаарлаж эсвэл унтраана.\n\n"<annotation id="url">"Нэмэлт мэдээлэл авах"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Батарей хэмнэгч нь Бараан загварыг асааж, дэвсгэрийн үйл ажиллагаа, зарим визуал эффект болон тодорхой онцлогуудийг хязгаарлаж эсвэл унтраана."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Дата ашиглалтыг багасгахын тулд дата хэмнэгч нь ар талд ажиллаж буй зарим апп-н өгөгдлийг илгээх болон авахаас сэргийлдэг. Таны одоогийн ашиглаж буй апп нь өгөгдөлд хандах боломжтой хэдий ч тогтмол хандахгүй. Энэ нь жишээлбэл зургийг товших хүртэл харагдахгүй гэсэн үг юм."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Дата хэмнэгчийг асаах уу?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Асаах"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Энэ мэдэгдлийг Чимээгүй болгож зэргийг нь бууруулсан байна. Санал хүсэлт өгөхийн тулд товшино уу."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Энэ мэдэгдлийг дээгүүр зэрэглэсэн байна. Санал хүсэлт өгөхийн тулд товшино уу."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Энэ мэдэгдлийг доогуур зэрэглэсэн байна. Санал хүсэлт өгөхийн тулд товшино уу."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Сайжруулсан мэдэгдлийг турших"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Санал болгосон үйлдэл, хариу болон илүү ихийг үргэлжлүүлэн авахын тулд сайжруулсан мэдэгдлийг асаана уу. Android-н Орчинтой тохирсон мэдэгдлийг дэмжихээ больсон байна."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Асаах"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Одоо биш"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Нэмэлт мэдээлэл авах"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Сайжруулсан мэдэгдэл нь харилцагчийн нэр, мессеж зэрэг хувийн мэдээллийг оруулаад бүх мэдэгдлийн контентыг унших боломжтой. Энэ онцлог мөн мэдэгдлийг хаах эсвэл утасны дуудлагад хариулах гэх мэт мэдэгдэл дэх товчлуур дээр үйлдэл хийх боломжтой.\n\nЭнэ онцлог мөн Чухал горимыг асаах, унтраах болон холбогдох тохиргоог өөрчлөх боломжтой."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Хэвшлийн горимын мэдээллийн мэдэгдэл"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батарей ихэвчлэн цэнэглэдэг хугацаанаас өмнө дуусаж болзошгүй"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Батарейн ажиллах хугацааг уртасгахын тулд Батарей хэмнэгчийг идэвхжүүллээ"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 9beb59f..ba20d59 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"अज्ञात पोट्रेट"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"अज्ञात लँडस्केप"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"रद्द केले"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"आपल्या प्रशासकाने अपडेट केले"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"आपल्या प्रशासकाने हटवले"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ओके"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"बॅटरी सेव्हर गडद थीम सुरू करते आणि बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट व “Ok Google” सारखी वैशिष्ट्ये मर्यादित किंवा बंद करते\n\n"<annotation id="url">"अधिक जाणून घ्या"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"बॅटरी सेव्हर गडद थीम सुरू करते आणि बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट व “Ok Google” सारखी वैशिष्ट्ये मर्यादित किंवा बंद करते."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"बॅटरी सेव्हर गडद थीम सुरू करते आणि बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट व ठरावीक वैशिष्ट्ये मर्यादित किंवा बंद करते.\n\n"<annotation id="url">"अधिक जाणून घ्या"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"बॅटरी सेव्हर गडद थीम सुरू करते आणि बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट व ठरावीक वैशिष्ट्ये मर्यादित किंवा बंद करते."</string>
<string name="data_saver_description" msgid="4995164271550590517">"डेटाचा वापर कमी करण्यात मदत करण्यासाठी काही अॅप्सना बॅकग्राउंडमध्ये डेटा पाठवण्यास किंवा मिळवण्यास डेटा सर्व्हर प्रतिबंध करतो. तुम्ही सध्या वापरत असलेले अॅप डेटा अॅक्सेस करू शकते, पण तसे खूप कमी वेळा होते. याचाच अर्थ असा की, तुम्ही इमेजवर टॅप करेपर्यंत त्या डिस्प्ले होणार नाहीत असे होऊ शकते."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा सेव्हर सुरू करायचे?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"सुरू करा"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ही सूचना सायलंट करण्यात आली आहे. फीडबॅक देण्यासाठी टॅप करा."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"हा सूचनेला उच्च रँक करण्यात आले. फीडबॅक देण्यासाठी टॅप करा."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"या सूचनेला कमी रँक करण्यात आले. फीडबॅक देण्यासाठी टॅप करा."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"वर्धित सूचना वापरून पहा"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"सुचवलेल्या कृती, उत्तरे आणि आणखी बरेच काही मिळवत राहण्यासाठी, वर्धित सूचना सुरू करा. Android अॅडॅप्टिव्ह सूचना यांना आता सपोर्ट नाही."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"सुरू करा"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"आता नको"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"वर्धित सूचना"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"सुचवलेल्या कृती आणि उत्तरे आता वर्धित सूचनांद्वारे दिल्या जातात. Android अॅडॅप्टिव्ह सूचना यांना आता सपोर्ट नाही."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ओके"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"बंद करा"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"अधिक जाणून घ्या"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"संपर्कांची नावे आणि मेसेज यांसारख्या वैयक्तिक माहितीच्या समावेशासह वर्धित सूचना या सर्व सूचनांचा आशय वाचू शकतात. हे वैशिष्ट्य सूचना डिसमिस करू शकते किंवा फोन कॉलना उत्तर देण्यासारख्या सूचनांमधील बटणवर कृतीदेखील करू शकते.\n\nहे वैशिष्ट्य प्राधान्य मोड सुरू किंवा बंद करू शकते आणि संबंधित सेटिंग्जदेखील बदलू शकते."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12 मधील Android अॅडॅप्टिव्ह सूचना यांना आता वर्धित सूचनांनी बदलले आहे. हे वैशिष्ट्य सुचवलेल्या कृती आणि उत्तरे दाखवते व तुमच्या सूचना व्यवस्थापित करते.\n\nवर्धित सूचना या संपर्कांची नावे आणि मेसेज यांसारख्या वैयक्तिक माहितीसह सर्व सूचनांचा आशय अॅक्सेस करू शकतात. हे वैशिष्ट्य फोन कॉलना उत्तर देणे आणि व्यत्यय आणू नका नियंत्रित करणे यांसारख्या कृती करून सूचना डिसमिस करू शकते किंवा त्यांना प्रतिसाद देऊ शकते."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"दिनक्रम मोडची माहिती सूचना"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"चार्जिंगची सामान्य पातळी गाठेपर्यंत कदाचित बॅटरी संपू शकते"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"बॅटरी लाइफ वाढवण्यासाठी बॅटरी सेव्हर सुरू केला आहे"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 62298a9..4d55195 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarki"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Kertas kajang"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Potret tidak diketahui"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Landskap tidak diketahui"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Dibatalkan"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Dikemas kini oleh pentadbir anda"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Dipadamkan oleh pentadbir anda"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Penjimat Bateri menghidupkan Tema gelap dan mengehadkan atau mematikan aktiviti latar, sesetengah kesan visual dan ciri seperti \"Ok Google\"\n\n"<annotation id="url">"Ketahui lebih lanjut"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Penjimat Bateri menghidupkan Tema gelap dan mengehadkan atau mematikan aktiviti latar, sesetengah kesan visual dan ciri seperti \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Penjimat Bateri menghidupkan tema Gelap dan mengehadkan atau mematikan aktiviti latar, sesetengah kesan visual dan ciri tertentu.\n\n"<annotation id="url">"Ketahui lebih lanjut"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Penjimat Bateri menghidupkan tema Gelap dan mengehadkan atau mematikan aktiviti latar, sesetengah kesan visual dan ciri tertentu."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Untuk membantu penggunaan data dikurangkan, Penjimat Data menghalang sesetengah apl daripada menghantar atau menerima data di latar. Apl yang sedang digunakan boleh mengakses data tetapi mungkin tidak secara kerap. Perkara ini mungkin bermaksud bahawa imej tidak dipaparkan sehingga anda mengetik pada imej itu, contohnya."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Hidupkan Penjimat Data?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Hidupkan"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Pemberitahuan ini telah diturun taraf kepada Senyap. Ketik untuk memberikan maklum balas."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Pemberitahuan ini berada di kedudukan lebih tinggi. Ketik untuk memberikan maklum balas."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Pemberitahuan ini berada di kedudukan lebih rendah. Ketik untuk memberikan maklum balas."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Cuba pemberitahuan dipertingkatkan"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Untuk terus mendapatkan tindakan yang dicadangkan, balasan dan banyak lagi, hidupkan pemberitahuan yang dipertingkatkan. Pemberitahuan Boleh Suai Android tidak disokong lagi."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Hidupkan"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Bukan sekarang"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Pemberitahuan dipertingkatkan"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Tindakan dan balasan yang dicadangkan kini disediakan oleh pemberitahuan yang dipertingkatkan. Pemberitahuan Boleh Suai Android tidak disokong lagi."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Matikan"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Ketahui lebih lanjut"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Pemberitahuan yang dipertingkatkan dapat membaca semua kandungan pemberitahuan, termasuk maklumat peribadi seperti nama kenalan dan mesej. Ciri ini juga dapat mengetepikan pemberitahuan atau mengambil tindakan pada butang dalam pemberitahuan, seperti menjawab panggilan telefon.\n\nCiri ini juga dapat menghidupkan atau mematikan mod Keutamaan dan menukar tetapan yang berkaitan."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Pemberitahuan yang dipertingkatkan menggantikan Pemberitahuan Boleh Suai Android dalam Android 12. Ciri ini menunjukkan tindakan dan balasan yang dicadangkan, serta mengatur pemberitahuan anda.\n\nPemberitahuan yang dipertingkatkan dapat mengakses kandungan pemberitahuan, termasuk maklumat peribadi seperti nama kenalan dan mesej. Ciri ini juga dapat mengetepikan atau membalas pemberitahuan, seperti menjawab panggilan telefon dan mengawal Jangan Ganggu."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Pemberitahuan maklumat Mod Rutin"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateri mungkin habis sebelum pengecasan biasa"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Penjimat Bateri diaktifkan untuk memanjangkan hayat bateri"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 9c6593e..43ed918 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"မိုနာချ့်"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"ကွာတို"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"ဖူးစကဒ်"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"အာအိုစီ ၈ကေ"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"အာအိုစီ ၁၆ကေ"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"ပီအာစီ ၁"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"ကဟူ"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"ကဟူ၂"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"ယူ၄"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"ဒေါင်လိုက် အရွယ်မသိ"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"အလျားလိုက် အရွယ်မသိ"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ဖျက်သိမ်းလိုက်ပြီး"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"သင်၏ စီမံခန့်ခွဲသူက အပ်ဒိတ်လုပ်ထားသည်"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"သင်၏ စီမံခန့်ခွဲသူက ဖျက်လိုက်ပါပြီ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"‘ဘက်ထရီ အားထိန်း’ က ‘မှောင်သည့် အပြင်အဆင်’ ကို ဖွင့်ပြီး နောက်ခံလုပ်ဆောင်ချက်၊ ပြသမှုဆိုင်ရာ အထူးပြုလုပ်ချက်အချို့နှင့် “Ok Google” ကဲ့သို့ ဝန်ဆောင်မှုများကို ကန့်သတ်သည် (သို့) ပိတ်သည်\n\n"<annotation id="url">"ပိုမိုလေ့လာရန်"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"‘ဘက်ထရီ အားထိန်း’ က ‘မှောင်သည့် အပြင်အဆင်’ ကို ဖွင့်ပြီး နောက်ခံလုပ်ဆောင်ချက်၊ ပြသမှုဆိုင်ရာ အထူးပြုလုပ်ချက်အချို့နှင့် “Ok Google” ကဲ့သို့ ဝန်ဆောင်မှုများကို ကန့်သတ်သည် (သို့) ပိတ်သည်။"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"‘ဘက်ထရီ အားထိန်း’ က ‘မှောင်သည့် အပြင်အဆင်’ ကို ဖွင့်ပြီး နောက်ခံလုပ်ဆောင်ချက်၊ ပြသမှုဆိုင်ရာ အထူးပြုလုပ်ချက်အချို့နှင့် ဝန်ဆောင်မှုအချို့ကို ကန့်သတ်သည် သို့မဟုတ် ပိတ်သည်။\n\n"<annotation id="url">"ပိုမိုလေ့လာရန်"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"‘ဘက်ထရီ အားထိန်း’ က ‘မှောင်သည့် အပြင်အဆင်’ ကို ဖွင့်ပြီး နောက်ခံလုပ်ဆောင်ချက်၊ ပြသမှုဆိုင်ရာ အထူးပြုလုပ်ချက်အချို့နှင့် ဝန်ဆောင်မှုအချို့ကို ကန့်သတ်သည် သို့မဟုတ် ပိတ်သည်။"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ဒေတာအသုံးလျှော့ချနိုင်ရန်အတွက် အက်ပ်များကို နောက်ခံတွင် ဒေတာပို့ခြင်းနှင့် လက်ခံခြင်းမပြုရန် \'ဒေတာချွေတာမှု\' စနစ်က တားဆီးထားပါသည်။ ယခုအက်ပ်ဖြင့် ဒေတာအသုံးပြုနိုင်သော်လည်း အကြိမ်လျှော့၍သုံးရပါမည်။ ဥပမာ၊ သင်က မတို့မချင်း ပုံများပေါ်လာမည် မဟုတ်ပါ။"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ဒေတာချွေတာမှုစနစ် ဖွင့်မလား။"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ဖွင့်ပါ"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ဤအကြောင်းကြားချက်ကို \'အသံတိတ်ခြင်း\' သို့ ပြန်ချိန်ညှိထားသည်။ အကြံပြုချက်ပေးရန် တို့ပါ။"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ဤအကြောင်းကြားချက်ကို အဆင့်တိုးထားသည်။ အကြံပြုချက်ပေးရန် တို့ပါ။"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ဤအကြောင်းကြားချက်ကို အဆင့်လျှော့ထားသည်။ အကြံပြုချက်ပေးရန် တို့ပါ။"</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"အဆင့်မြင့် အကြောင်းကြားချက်များ စမ်းသုံးကြည့်ခြင်း"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"အကြံပြုထားသော လုပ်ဆောင်ချက်များ၊ ပြန်စာများ စသည်တို့ကို ဆက်လက်ရယူရန် အဆင့်မြင့် အကြောင်းကြားချက်များကို ဖွင့်ပါ။ ‘Android အလိုက်သင့် အကြောင်းကြားချက်များ’ ကို ပံ့ပိုးမထားတော့ပါ။"</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ဖွင့်ရန်"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ယခုမလုပ်ပါ"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ပိုမိုလေ့လာရန်"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"အဆင့်မြင့် အကြောင်းကြားချက်များသည် အဆက်အသွယ်အမည်နှင့် မက်ဆေ့ဂျ်များကဲ့သို့ ကိုယ်ရေးကိုယ်တာအချက်လက်များ အပါအဝင် အကြောင်းကြားချက် အကြောင်းအရာအားလုံးကို ဖတ်နိုင်သည်။ ဤဝန်ဆောင်မှုသည် အကြောင်းကြားချက်များကို ပယ်ခြင်း (သို့) ဖုန်းခေါ်ဆိုမှုများ ဖြေခြင်းကဲ့သို့ အကြောင်းကြားချက်များရှိ ခလုတ်များ နှိပ်ခြင်းကိုလည်း ပြုလုပ်နိုင်သည်။\n\nဤဝန်ဆောင်မှုသည် ‘ဦးစားပေးမုဒ်’ ကို ဖွင့်ခြင်း (သို့) ပိတ်ခြင်း ပြုလုပ်နိုင်ပြီး ဆက်စပ်နေသော ဆက်တင်များကိုလည်း ပြောင်းနိုင်သည်။"</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ပုံမှန်မုဒ်အတွက် အချက်အလက်ပြသည့် အကြောင်းကြားချက်"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ပုံမှန်အားသွင်းမှုမပြုလုပ်မီ ဘက်ထရီကုန်သွားနိုင်သည်"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ဘက်ထရီသက်တမ်းကို တိုးမြှင့်ရန် \'ဘက်ထရီအားထိန်း\' စတင်ပြီးပါပြီ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 4720e29..5baea2c 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Ukjent portrett"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Ukjent landskap"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Kansellert"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Oppdatert av administratoren din"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet av administratoren din"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Batterisparing slår på mørkt tema og begrenser eller slår av bakgrunnsaktivitet, enkelte visuelle effekter og funksjoner, for eksempel «Hey Google»\n\n"<annotation id="url">"Finn ut mer"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Batterisparing slår på mørkt tema og begrenser eller slår av bakgrunnsaktivitet, enkelte visuelle effekter og funksjoner, for eksempel «Hey Google»."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Batterisparing slår på mørkt tema og begrenser eller slår av bakgrunnsaktivitet, enkelte visuelle effekter og noen funksjoner.\n\n"<annotation id="url">"Finn ut mer"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Batterisparing slår på mørkt tema og begrenser eller slår av bakgrunnsaktivitet, enkelte visuelle effekter og noen funksjoner."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Datasparing hindrer noen apper fra å sende og motta data i bakgrunnen, for å redusere dataforbruket. Aktive apper kan bruke data, men kanskje ikke så mye som ellers – for eksempel vises ikke bilder før du trykker på dem."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vil du slå på Datasparing?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Slå på"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Dette varselet ble nedgradert til lydløst. Trykk for å gi tilbakemelding."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Dette varselet ble rangert høyere. Trykk for å gi tilbakemelding."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Dette varselet ble rangert lavere. Trykk for å gi tilbakemelding."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Prøv forbedrede varsler"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"For å fortsette å få foreslåtte handlinger, svar med mer, slå på forbedrede varsler. Tilpassede Android-varsler støttes ikke lenger."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Slå på"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ikke nå"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Forbedrede varsler"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Foreslåtte handlinger og svar leveres nå i forbedrede varsler. Tilpassede Android-varsler støttes ikke lenger."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Slå av"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Finn ut mer"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Forbedrede varsler kan lese alt varselinnhold, inkludert personopplysninger som kontaktnavn og meldinger. Denne funksjonen kan også avvise varsler eller bruke knapper i varsler, for eksempel for å svare på telefonanrop.\n\nDenne funksjonen kan også slå prioriteringsmodus på eller av og endre relaterte innstillinger."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Forbedrede varsler erstatter tilpassede Android-varsler i Android 12. Denne funksjonen viser foreslåtte handlinger og svar og organiserer varslene dine.\n\nForbedrede varsler har tilgang til varselinnhold, inkludert personopplysninger som kontaktnavn og meldinger. Funksjonen kan også avvise og svare på varsler, for eksempel svare på anrop og kontrollere «Ikke forstyrr»."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Varsel med informasjon om rutinemodus"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batteriet kan gå tomt før den vanlige ladingen"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterisparing er aktivert for å forlenge batterilevetiden"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 458e09b..5c9382a 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -246,7 +246,7 @@
<string name="global_action_lock" msgid="6949357274257655383">"स्क्रिन बन्द"</string>
<string name="global_action_power_off" msgid="4404936470711393203">"बन्द गर्नुहोस्"</string>
<string name="global_action_power_options" msgid="1185286119330160073">"पावर"</string>
- <string name="global_action_restart" msgid="4678451019561687074">"पुनः सुरु गर्नुहोस्"</string>
+ <string name="global_action_restart" msgid="4678451019561687074">"रिस्टार्ट गर्नुहोस्"</string>
<string name="global_action_emergency" msgid="1387617624177105088">"आपत्कालीन"</string>
<string name="global_action_bug_report" msgid="5127867163044170003">"बग रिपोर्ट"</string>
<string name="global_action_logout" msgid="6093581310002476511">"सत्रको अन्त्य गर्नुहोस्"</string>
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"मोनार्क"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"क्वार्टो"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"फुलस्केप"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super-B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,8 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <!-- no translation found for mediasize_japanese_l (1326765321473431817) -->
+ <skip />
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"अज्ञात चित्र"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"अज्ञात परिदृश्य"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"रद्द गरियो"</string>
@@ -1852,9 +1865,9 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"तपाईंका प्रशासकले अद्यावधिक गर्नुभएको"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"तपाईंका प्रशासकले मेट्नुभएको"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ठिक छ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (7963058670863485450) -->
+ <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) -->
<skip />
- <!-- no translation found for battery_saver_description (7695751399533397741) -->
+ <!-- no translation found for battery_saver_description (5693741424234005958) -->
<skip />
<string name="data_saver_description" msgid="4995164271550590517">"डेटा सेभरले डेटा खपत कम गर्न केही एपहरूलाई ब्याकग्राउन्डमा डेटा पठाउन वा प्राप्त गर्न दिँदैन। तपाईंले अहिले प्रयोग गरिरहनुभएको एपले सीमित रूपमा मात्र डेटा चलाउन पाउँछ। उदाहरणका लागि, तपाईंले फोटोमा ट्याप गर्नुभयो भने मात्र फोटो देखिन्छ नत्र देखिँदैन।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा सेभर अन गर्ने हो?"</string>
@@ -1902,7 +1915,7 @@
<string name="zen_mode_downtime_feature_name" msgid="5886005761431427128">"डाउनटाइम"</string>
<string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"हरेक हप्तादिनको राति"</string>
<string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"शनिबार"</string>
- <string name="zen_mode_default_events_name" msgid="2280682960128512257">"घटना"</string>
+ <string name="zen_mode_default_events_name" msgid="2280682960128512257">"कार्यक्रम"</string>
<string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"शयन अवस्था"</string>
<string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ले केही ध्वनिहरू म्युट गर्दै छ"</string>
<string name="system_error_wipe_data" msgid="5910572292172208493">"तपाईंको यन्त्रसँग आन्तरिक समस्या छ, र तपाईंले फ्याक्ट्री डाटा रिसेट नगर्दासम्म यो अस्थिर रहन्छ।"</string>
@@ -1931,8 +1944,7 @@
<string name="close_button_text" msgid="10603510034455258">"बन्द गर्नुहोस्"</string>
<string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
<string name="call_notification_answer_action" msgid="5999246836247132937">"कलको जवाफ दिनु…"</string>
- <!-- no translation found for call_notification_answer_video_action (2086030940195382249) -->
- <skip />
+ <string name="call_notification_answer_video_action" msgid="2086030940195382249">"भिडियो"</string>
<string name="call_notification_decline_action" msgid="3700345945214000726">"अस्वीकार गर्नुहोस्"</string>
<string name="call_notification_hang_up_action" msgid="9130720590159188131">"फोन राख्नुहोस्"</string>
<string name="call_notification_incoming_text" msgid="6143109825406638201">"आगमन कल"</string>
@@ -2076,17 +2088,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"यस सूचनालाई कम महत्त्वपूर्ण ठानी यसका लागि साइलेन्ट मोड सेट गरिएको छ। प्रतिक्रिया दिन ट्याप गर्नुहोस्।"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"यस सूचनालाई धेरै महत्त्वपूर्ण सूचनाका रूपमा सेट गरिएको छ। प्रतिक्रिया दिन ट्याप गर्नुहोस्।"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"यस सूचनालाई कम महत्त्वपूर्ण सूचनाका रूपमा सेट गरिएको छ। प्रतिक्रिया दिन ट्याप गर्नुहोस्।"</string>
- <!-- no translation found for nas_upgrade_notification_title (4224351129445073051) -->
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
<skip />
- <!-- no translation found for nas_upgrade_notification_content (7036860187157134706) -->
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
<skip />
- <!-- no translation found for nas_upgrade_notification_enable_action (4823652531622744798) -->
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
<skip />
- <!-- no translation found for nas_upgrade_notification_disable_action (7561210256700811433) -->
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
<skip />
<!-- no translation found for nas_upgrade_notification_learn_more_action (7011130656195423947) -->
<skip />
- <!-- no translation found for nas_upgrade_notification_learn_more_content (6276343083934111208) -->
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
<skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"दिनचर्या मोडको जानकारीमूलक सूचना"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"प्रायः चार्ज गर्ने समय हुनुभन्दा पहिले नै ब्याट्री सकिन सक्छ"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index fcc5264..2dab66e 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1108,8 +1108,8 @@
<item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> minuut geleden</item>
</plurals>
<plurals name="duration_hours_relative" formatted="false" msgid="420434788589102019">
- <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> uur geleden, </item>
- <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> uur geleden, </item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> uur geleden</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> uur geleden</item>
</plurals>
<plurals name="duration_days_relative" formatted="false" msgid="6056425878237482431">
<item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> dagen geleden</item>
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Onbekend staand"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Onbekend liggend"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Geannuleerd"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Geüpdatet door je beheerder"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Verwijderd door je beheerder"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Batterijbesparing zet het donkere thema aan en beperkt achtergrondactiviteit, bepaalde visuele effecten en functies zoals Hey Google of zet dit uit\n\n"<annotation id="url">"Meer informatie"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Batterijbesparing zet het donkere thema aan en beperkt achtergrondactiviteit, bepaalde visuele effecten en functies zoals Hey Google of zet dit uit."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Met Batterijbesparing wordt het donkere thema aangezet en worden achtergrondactiviteit, sommige visuele effecten en bepaalde functies beperkt of uitgezet.\n\n"<annotation id="url">"Meer informatie"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Met Batterijbesparing wordt het donkere thema aangezet en worden achtergrondactiviteit, sommige visuele effecten en bepaalde functies beperkt of uitgezet."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Databesparing beperkt het datagebruik door te voorkomen dat sommige apps gegevens sturen of ontvangen op de achtergrond. De apps die je open hebt, kunnen nog steeds data verbruiken, maar doen dit minder vaak. Afbeeldingen worden dan bijvoorbeeld niet weergegeven totdat je erop tikt."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Databesparing aanzetten?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aanzetten"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Deze melding is verlaagd naar Stil. Tik om feedback te geven."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Deze melding is hoger geclassificeerd. Tik om feedback te geven."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Deze melding is lager geclassificeerd. Tik om feedback te geven."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Probeer verbeterde meldingen"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Activeer verbeterde meldingen om voorgestelde acties, antwoorden en meer te blijven ontvangen. Aanpasbare Android-meldingen worden niet meer ondersteund."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aanzetten"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Niet nu"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Verbeterde meldingen"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Voorgestelde acties en antwoorden worden nu geleverd via verbeterde meldingen. Aanpasbare Android-meldingen worden niet meer ondersteund."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Uitzetten"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Meer informatie"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Verbeterde meldingen kunnen alle meldingscontent lezen, waaronder persoonlijke informatie zoals contactnamen en berichten. Deze functie kan ook meldingen sluiten of acties uitvoeren voor knoppen in meldingen, zoals telefoongesprekken aannemen.\n\nDeze functie kan ook de prioriteitsmodus aan- of uitzetten en gerelateerde instellingen wijzigen."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"In Android 12 hebben verbeterde meldingen aanpasbare Android-meldingen vervangen. Deze functie laat voorgestelde acties en antwoorden zien en ordent je meldingen.\n\nVerbeterde meldingen hebben toegang tot meldingscontent, waaronder persoonlijke informatie zoals contactnamen en berichten. Deze functie kan ook meldingen sluiten of erop reageren, zoals telefoongesprekken aannemen en Niet storen beheren."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Informatiemelding voor routinemodus"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"De batterij raakt mogelijk leeg voordat deze normaal gesproken wordt opgeladen"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterijbesparing is geactiveerd om de batterijduur te verlengen"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 55bb315..8a63f06 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"ମୋନାର୍କ"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"କ୍ୱାର୍ଟୋ"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,8 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <!-- no translation found for mediasize_japanese_l (1326765321473431817) -->
+ <skip />
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"ଅଜଣା ପୋର୍ଟ୍ରେଟ୍"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"ଅଜଣା ଲ୍ୟାଣ୍ଡସ୍କେପ୍"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ବାତିଲ୍ କରାଗଲା"</string>
@@ -1852,8 +1865,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ଆପଣଙ୍କ ଆଡମିନ୍ ଅପଡେଟ୍ କରିଛନ୍ତି"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ଆପଣଙ୍କ ଆଡମିନ୍ ଡିଲିଟ୍ କରିଛନ୍ତି"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ଠିକ୍ ଅଛି"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"ବ୍ୟାଟେରୀ ସେଭର୍ ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ ଏବଂ ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ୍ ଇଫେକ୍ଟ ଏବଂ “Hey Google” ପରି ଫିଚରଗୁଡ଼ିକୁ ସୀମିତ କିମ୍ବା ବନ୍ଦ କରେ\n\n"<annotation id="url">"ଅଧିକ ଜାଣନ୍ତୁ"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"ବ୍ୟାଟେରୀ ସେଭର୍ ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ ଏବଂ ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ୍ ଇଫେକ୍ଟ ଏବଂ “Hey Google” ପରି ଫିଚରଗୁଡ଼ିକୁ ସୀମିତ କିମ୍ବା ବନ୍ଦ କରେ।"</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (5693741424234005958) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"ଡାଟା ବ୍ୟବହାର କମ୍ କରିବାରେ ସାହାଯ୍ୟ କରିବାକୁ, ଡାଟା ସେଭର୍ ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡରେ ଡାଟା ପଠାଇବା କିମ୍ବା ପ୍ରାପ୍ତ କରିବାକୁ କିଛି ଆପ୍କୁ ବାରଣ କରେ। ଆପଣ ବର୍ତ୍ତମାନ ବ୍ୟବହାର କରୁଥିବା ଆପ୍, ଡାଟା ଆକ୍ସେସ୍ କରିପାରେ, କିନ୍ତୁ ଏହା କମ୍ ଥର କରିପାରେ। ଏହାର ଅର୍ଥ ହୋଇପାରେ ଯେମିତି ଆପଣ ଇମେଜଗୁଡ଼ିକୁ ଟାପ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ସେଗୁଡ଼ିକ ଡିସପ୍ଲେ ହୁଏ ନାହିଁ।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ଡାଟା ସେଭର୍ ଚାଲୁ କରିବେ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ଚାଲୁ କରନ୍ତୁ"</string>
@@ -2073,12 +2088,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ଏହି ବିଜ୍ଞପ୍ତିକୁ ନୀରବ ଭାବେ ଡିମୋଟ୍ କରାଯାଇଛି। ମତାମତ ପ୍ରଦାନ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ଏହି ବିଜ୍ଞପ୍ତିର ରେଙ୍କ ଉପରକୁ କରାଯାଇଛି। ମତାମତ ପ୍ରଦାନ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ଏହି ବିଜ୍ଞପ୍ତିର ରେଙ୍କ ତଳକୁ କରାଯାଇଛି। ମତାମତ ପ୍ରଦାନ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"ଉନ୍ନତ ବିଜ୍ଞପ୍ତି ବ୍ୟବହାରକରି ଦେଖ"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"ପ୍ରସ୍ତାବିତ କାର୍ଯ୍ୟ, ପ୍ରତ୍ୟୁତ୍ତର ଏବଂ ଆହୁରି ଅନେକ କିଛି ପାଇବା ଜାରି ରଖିବାକୁ, ଉନ୍ନତ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଚାଲୁ କରନ୍ତୁ। Android ଆଡେପ୍ଟିଭ୍ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଆଉ ସମର୍ଥିତ ନୁହେଁ।"</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ଚାଲୁ କରନ୍ତୁ"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ବର୍ତ୍ତମାନ ନୁହେଁ"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ଅଧିକ ଜାଣନ୍ତୁ"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"ଉନ୍ନତ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଯୋଗାଯୋଗ ନାମ ଏବଂ ମେସେଜଗୁଡ଼ିକ ପରି ବ୍ୟକ୍ତିଗତ ସୂଚନା ସମେତ ସମସ୍ତ ବିଜ୍ଞପ୍ତି ବିଷୟବସ୍ତୁକୁ ପଢ଼ିପାରିବ। ଏହି ଫିଚର୍ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଖାରଜ କରିପାରିବ କିମ୍ବା ଫୋନ୍ କଲଗୁଡ଼ିକର ଉତ୍ତର ଦେବା ପରି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକରେ ଥିବା ବଟନଗୁଡ଼ିକ ଉପରେ ପଦକ୍ଷେପ ମଧ୍ୟ ନେଇପାରିବ।\n\nଏହି ଫିଚର୍ ପ୍ରାଥମିକତା ମୋଡକୁ ଚାଲୁ କିମ୍ବା ବନ୍ଦ କରିପାରିବ ଏବଂ ସମ୍ବନ୍ଧିତ ସେଟିଂସକୁ ପରିବର୍ତ୍ତନ ମଧ୍ୟ କରିପାରିବ।"</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ନିୟମିତ ମୋଡ୍ ସୂଚନା ବିଜ୍ଞପ୍ତି"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ସାଧାରଣ ଭାବରେ ଚାର୍ଜ୍ କରିବା ପୂର୍ବରୁ ବ୍ୟାଟେରୀ ସରିଯାଇପାରେ"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ବ୍ୟାଟେରୀର ସମୟକୁ ବଢ଼ାଇବା ପାଇଁ ବ୍ୟଟେରୀ ସେଭର୍କୁ କାର୍ଯ୍ୟକାରୀ କରାଯାଇଛି"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index bfa5760..1711a88 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"ਸਮਰਾਟ"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"ਚੁਪੱਤਰੀ"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,8 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <!-- no translation found for mediasize_japanese_l (1326765321473431817) -->
+ <skip />
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"ਅਗਿਆਤ ਪੋਰਟਰੇਟ"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"ਅਗਿਆਤ ਲੈਂਡਸਕੇਪ"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ਰੱਦ ਕੀਤਾ ਗਿਆ"</string>
@@ -1852,8 +1865,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਮਿਟਾਇਆ ਗਿਆ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ਠੀਕ ਹੈ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"ਬੈਟਰੀ ਸੇਵਰ ਗੂੜ੍ਹੇ ਥੀਮ ਨੂੰ ਚਾਲੂ ਕਰਦਾ ਹੈ ਅਤੇ ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ ਅਤੇ \"Ok Google\" ਵਰਗੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਸੀਮਤ ਕਰਦਾ ਹੈ ਜਾਂ ਬੰਦ ਕਰਦਾ ਹੈ\n\n"<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"ਬੈਟਰੀ ਸੇਵਰ ਗੂੜ੍ਹੇ ਥੀਮ ਨੂੰ ਚਾਲੂ ਕਰਦਾ ਹੈ ਅਤੇ ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ ਅਤੇ \"Ok Google\" ਵਰਗੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਸੀਮਤ ਕਰਦਾ ਹੈ ਜਾਂ ਬੰਦ ਕਰਦਾ ਹੈ।"</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (5693741424234005958) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"ਡਾਟਾ ਵਰਤੋਂ ਘਟਾਉਣ ਵਿੱਚ ਮਦਦ ਲਈ, ਡਾਟਾ ਸੇਵਰ ਕੁਝ ਐਪਾਂ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਡਾਟਾ ਭੇਜਣ ਜਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਤੋਂ ਰੋਕਦਾ ਹੈ। ਤੁਹਾਡੇ ਵੱਲੋਂ ਵਰਤਮਾਨ ਤੌਰ \'ਤੇ ਵਰਤੀ ਜਾ ਰਹੀ ਐਪ ਡਾਟਾ \'ਤੇ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ, ਪਰ ਉਹ ਇੰਝ ਕਦੇ-ਕਦਾਈਂ ਕਰ ਸਕਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਸ ਦਾ ਮਤਲਬ ਇਹ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਚਿੱਤਰ ਤਦ ਤੱਕ ਨਹੀਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕੀਤੇ ਜਾਂਦੇ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਉਹਨਾਂ \'ਤੇ ਟੈਪ ਨਹੀਂ ਕਰਦੇ।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ਕੀ ਡਾਟਾ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ਚਾਲੂ ਕਰੋ"</string>
@@ -2073,12 +2088,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ਇਸ ਸੂਚਨਾ ਦਾ ਦਰਜਾ ਘਟਾ ਕੇ ਸ਼ਾਂਤ \'ਤੇ ਸੈੱਟ ਕੀਤਾ ਗਿਆ। ਵਿਚਾਰ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ਇਸ ਸੂਚਨਾ ਦਾ ਦਰਜਾ ਵਧਾ ਦਿੱਤਾ ਗਿਆ। ਵਿਚਾਰ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ਇਸ ਸੂਚਨਾ ਦਾ ਦਰਜਾ ਘਟਾ ਦਿੱਤਾ ਗਿਆ। ਵਿਚਾਰ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"ਵਿਸਤ੍ਰਿਤ ਸੂਚਨਾਵਾਂ ਅਜ਼ਮਾਓ"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"ਸੁਝਾਈਆਂ ਗਈਆਂ ਕਾਰਵਾਈਆਂ, ਜਵਾਬਾਂ ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਦੇ ਰਹਿਣ ਲਈ, ਵਿਸਤ੍ਰਿਤ ਸੂਚਨਾਵਾਂ ਨੂੰ ਚਾਲੂ ਕਰੋ। Android ਅਡੈਪਟਿਵ ਸੂਚਨਾਵਾਂ ਹੁਣ ਸਮਰਥਿਤ ਨਹੀਂ ਹਨ।"</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ਚਾਲੂ ਕਰੋ"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ਹੁਣੇ ਨਹੀਂ"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ਹੋਰ ਜਾਣੋ"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"ਵਿਸਤ੍ਰਿਤ ਸੂਚਨਾਵਾਂ ਸਾਰੀ ਸੂਚਨਾ ਸਮੱਗਰੀ ਨੂੰ ਪੜ੍ਹ ਸਕਦੀਆਂ ਹਨ, ਜਿਸ ਵਿੱਚ ਸੰਪਰਕ ਨਾਮ ਅਤੇ ਸੁਨੇਹੇ ਵਰਗੀ ਨਿੱਜੀ ਜਾਣਕਾਰੀ ਵੀ ਸ਼ਾਮਲ ਹੈ। ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਸੂਚਨਾਵਾਂ ਨੂੰ ਖਾਰਜ ਵੀ ਕਰ ਸਕਦੀ ਹੈ ਜਾਂ ਸੂਚਨਾਵਾਂ ਵਿੱਚ ਬਟਨਾਂ \'ਤੇ ਕਾਰਵਾਈਆਂ ਵੀ ਕਰ ਸਕਦੀ ਹੈ, ਜਿਵੇਂ ਕਿ ਫ਼ੋਨ ਕਾਲਾਂ ਦਾ ਜਵਾਬ ਦੇਣਾ।\n\nਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਤਰਜੀਹੀ ਮੋਡ ਨੂੰ ਚਾਲੂ ਜਾਂ ਬੰਦ ਵੀ ਕਰ ਸਕਦੀ ਹੈ ਅਤੇ ਸੰਬੰਧਿਤ ਸੈਟਿੰਗਾਂ ਨੂੰ ਬਦਲ ਸਕਦੀ ਹੈ।"</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ਨਿਯਮਬੱਧ ਮੋਡ ਦੀ ਜਾਣਕਾਰੀ ਵਾਲੀ ਸੂਚਨਾ"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ਬੈਟਰੀ ਚਾਰਜ ਕਰਨ ਦੇ ਮਿੱਥੇ ਸਮੇਂ ਤੋਂ ਪਹਿਲਾਂ ਸ਼ਾਇਦ ਬੈਟਰੀ ਖਤਮ ਹੋ ਜਾਵੇ"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 57037ad..bc11c37 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1817,6 +1817,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1853,6 +1864,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Nieznany pionowy"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Nieznany poziomy"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Anulowane"</string>
@@ -1898,8 +1910,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Zaktualizowany przez administratora"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Usunięty przez administratora"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Oszczędzanie baterii uruchamia ciemny motyw oraz wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne i inne funkcje, np. „OK Google”\n\n"<annotation id="url">"Więcej informacji"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Oszczędzanie baterii uruchamia ciemny motyw oraz wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne i inne funkcje, np. „OK Google”."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Oszczędzanie baterii uruchamia ciemny motyw oraz wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne i wybrane funkcje.\n\n"<annotation id="url">"Więcej informacji"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Oszczędzanie baterii uruchamia ciemny motyw oraz wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne i wybrane funkcje."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Oszczędzanie danych uniemożliwia niektórym aplikacjom wysyłanie i odbieranie danych w tle, zmniejszając w ten sposób ich użycie. Aplikacja, z której w tej chwili korzystasz, może uzyskiwać dostęp do danych, ale rzadziej. Może to powodować, że obrazy będą się wyświetlać dopiero po kliknięciu."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Włączyć Oszczędzanie danych?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Włącz"</string>
@@ -2139,12 +2151,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"To powiadomienie zostało zmienione na Ciche. Kliknij, by przesłać opinię."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Podniesiono ważność tego powiadomienia. Kliknij, by przesłać opinię."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Obniżono ważność tego powiadomienia. Kliknij, by przesłać opinię."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Wypróbuj ulepszone powiadomienia"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Aby nadal otrzymywać sugestie działań oraz odpowiedzi i inne podpowiedzi, włącz ulepszone powiadomienia. Powiadomienia adaptacyjne w Androidzie nie są już obsługiwane."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Włącz"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Nie teraz"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Więcej informacji"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Ulepszone powiadomienia mogą czytać wszystkie powiadomienia, w tym dane osobowe takie jak nazwy kontaktów i treść wiadomości. Funkcja będzie też mogła odrzucać powiadomienia oraz używać zawartych w nich przycisków, np. odbierać połączenia telefoniczne.\n\nMoże również włączać i wyłączać tryb Priorytet oraz zmieniać powiązane ustawienia."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Powiadomienie z informacją o trybie rutynowym"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateria może się wyczerpać przed zwykłą porą ładowania"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Włączono Oszczędzanie baterii, by wydłużyć czas pracy na baterii"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 102073e..dd1ebb6 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Retrato desconhecido"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Paisagem desconhecido"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelado"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Excluído pelo seu administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"A Economia de bateria ativa o tema escuro e limita ou desativa as atividades em segundo plano, alguns efeitos visuais e recursos como o \"Ok Google\"\n\n"<annotation id="url">"Saiba mais"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"A Economia de bateria ativa o tema escuro e limita ou desativa as atividades em segundo plano, alguns efeitos visuais e recursos como o \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"A Economia de bateria ativa o tema escuro e limita ou desativa as atividades em segundo plano, alguns efeitos visuais e recursos específicos.\n\n"<annotation id="url">"Saiba mais"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"A Economia de bateria ativa o tema escuro e limita ou desativa as atividades em segundo plano, alguns efeitos visuais e recursos específicos."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar \"Economia de dados\"?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Esta notificação foi rebaixada a Silenciosa. Toque para enviar seu feedback."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Esta notificação foi classificada com maior prioridade. Toque para enviar seu feedback."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Esta notificação foi classificada com menor prioridade. Toque para enviar seu feedback."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Testar notif. aprimoradas"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Para continuar a receber sugestões de ações, respostas e muito mais, ative as notificações aprimoradas. As Notificações adaptáveis do Android não estão mais disponíveis."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Ativar"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Agora não"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notificações aprimoradas"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"As ações e respostas sugeridas agora são fornecidas pelas notificações aprimoradas. As Notificações adaptáveis do Android não estão mais disponíveis."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desativar"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saiba mais"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"As notificações aprimoradas podem ler todo o conteúdo das notificações, incluindo informações pessoais como nomes de contatos e mensagens. Além disso, esse recurso pode dispensar notificações e usar os botões delas para, por exemplo, atender chamadas telefônicas.\n\nEle também pode ativar ou desativar o modo Prioridade e mudar as configurações relacionadas."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"No Android 12, as notificações aprimoradas substituíram as Notificações adaptáveis. Esse recurso exibe ações e respostas sugeridas, além de organizar suas notificações.\n\nAs notificações aprimoradas podem acessar o conteúdo das notificações, incluindo informações pessoais como nomes de contatos e mensagens. Elas também podem dispensar ou responder às notificações, como atender chamadas telefônicas e controlar o Não perturbe."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificação de informação do modo rotina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"A bateria pode acabar antes da recarga normal"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"A Economia de bateria foi ativada para aumentar a duração da carga"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index d0c2beb..3b0a5ca 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Vertical desconhecido"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Horizontal desconhecido"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelada"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu gestor"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado pelo seu gestor"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"A Poupança de bateria ativa o tema escuro e limita ou desativa a atividade em segundo plano, alguns efeitos visuais e funcionalidades como \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"A Poupança de bateria ativa o tema escuro e limita ou desativa a atividade em segundo plano, alguns efeitos visuais e funcionalidades como \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"A Poupança de bateria ativa o tema escuro e limita ou desativa a atividade em segundo plano, alguns efeitos visuais e determinadas funcionalidades.\n\n"<annotation id="url">"Saiba mais"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"A Poupança de bateria ativa o tema escuro e limita ou desativa a atividade em segundo plano, alguns efeitos visuais e determinadas funcionalidades."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir a utilização de dados, a Poupança de dados impede que algumas aplicações enviem ou recebam dados em segundo plano. Uma determinada app que esteja a utilizar atualmente pode aceder aos dados, mas é possível que o faça com menos frequência. Isto pode significar, por exemplo, que as imagens não são apresentadas até que toque nas mesmas."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Pretende ativar a Poupança de dados?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Esta notificação foi despromovida para Silenciosa. Toque para fornecer feedback."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Esta notificação passou para uma classificação superior. Toque para fornecer feedback."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Esta notificação passou para uma classificação inferior. Toque para fornecer feedback."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Experimente as not. melhoradas"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Para continuar a obter sugestões de ações, respostas e muito mais, ative as notificações melhoradas. As notificações adaptáveis do Android já não são suportadas."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Ativar"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Agora não"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notificações melhoradas"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"As ações e as respostas sugeridas são agora fornecidas por notificações melhoradas. As notificações adaptáveis do Android já não são suportadas."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desativar"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saber mais"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"As notificações melhoradas podem ler todo o conteúdo das notificações, incluindo informações pessoais como nomes de contactos e mensagens. Esta funcionalidade também pode ignorar notificações ou acionar botões em notificações, como atender chamadas telefónicas.\n\nAlém disso, esta funcionalidades pode ativar ou desativar o modo Prioridade e alterar as definições relacionadas."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"As notificações melhoradas substituíram as notificações adaptáveis do Android no Android 12. Esta funcionalidade mostra ações e respostas sugeridas e organiza as suas notificações.\n\nAs notificações melhoradas podem aceder a todo o conteúdo das notificações, incluindo informações pessoais como nomes de contactos e mensagens. Esta funcionalidade também pode ignorar ou responder a notificações, como atender chamadas telefónicas e controlar o modo Não incomodar."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificação de informações do Modo rotina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Pode ficar sem bateria antes do carregamento habitual"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Poupança de bateria ativada para prolongar a duração da bateria"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 102073e..dd1ebb6 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Retrato desconhecido"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Paisagem desconhecido"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelado"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Excluído pelo seu administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"A Economia de bateria ativa o tema escuro e limita ou desativa as atividades em segundo plano, alguns efeitos visuais e recursos como o \"Ok Google\"\n\n"<annotation id="url">"Saiba mais"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"A Economia de bateria ativa o tema escuro e limita ou desativa as atividades em segundo plano, alguns efeitos visuais e recursos como o \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"A Economia de bateria ativa o tema escuro e limita ou desativa as atividades em segundo plano, alguns efeitos visuais e recursos específicos.\n\n"<annotation id="url">"Saiba mais"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"A Economia de bateria ativa o tema escuro e limita ou desativa as atividades em segundo plano, alguns efeitos visuais e recursos específicos."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar \"Economia de dados\"?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Esta notificação foi rebaixada a Silenciosa. Toque para enviar seu feedback."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Esta notificação foi classificada com maior prioridade. Toque para enviar seu feedback."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Esta notificação foi classificada com menor prioridade. Toque para enviar seu feedback."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Testar notif. aprimoradas"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Para continuar a receber sugestões de ações, respostas e muito mais, ative as notificações aprimoradas. As Notificações adaptáveis do Android não estão mais disponíveis."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Ativar"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Agora não"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notificações aprimoradas"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"As ações e respostas sugeridas agora são fornecidas pelas notificações aprimoradas. As Notificações adaptáveis do Android não estão mais disponíveis."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desativar"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saiba mais"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"As notificações aprimoradas podem ler todo o conteúdo das notificações, incluindo informações pessoais como nomes de contatos e mensagens. Além disso, esse recurso pode dispensar notificações e usar os botões delas para, por exemplo, atender chamadas telefônicas.\n\nEle também pode ativar ou desativar o modo Prioridade e mudar as configurações relacionadas."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"No Android 12, as notificações aprimoradas substituíram as Notificações adaptáveis. Esse recurso exibe ações e respostas sugeridas, além de organizar suas notificações.\n\nAs notificações aprimoradas podem acessar o conteúdo das notificações, incluindo informações pessoais como nomes de contatos e mensagens. Elas também podem dispensar ou responder às notificações, como atender chamadas telefônicas e controlar o Não perturbe."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificação de informação do modo rotina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"A bateria pode acabar antes da recarga normal"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"A Economia de bateria foi ativada para aumentar a duração da carga"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index e6b7ff6..f064932 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1795,6 +1795,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super-B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1831,6 +1842,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Portret necunoscut"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Peisaj necunoscut"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Anulat"</string>
@@ -1875,8 +1887,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizat de administratorul dvs."</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Șters de administratorul dvs."</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Economisirea bateriei activează Tema întunecată și limitează sau dezactivează activitatea din fundal, anumite efecte vizuale și funcții precum „Ok Google”\n\n"<annotation id="url">"Aflați mai multe"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Economisirea bateriei activează Tema întunecată și limitează sau dezactivează activitatea din fundal, anumite efecte vizuale și funcții precum „Ok Google”."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Economisirea bateriei activează tema întunecată și dezactivează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții.\n\n"<annotation id="url">"Aflați mai multe"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Economisirea bateriei activează tema întunecată și dezactivează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Pentru a contribui la reducerea utilizării de date, Economizorul de date împiedică unele aplicații să trimită sau să primească date în fundal. O aplicație pe care o folosiți poate accesa datele, însă mai rar. Aceasta poate însemna, de exemplu, că imaginile se afișează numai după ce le atingeți."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activați Economizorul de date?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activați"</string>
@@ -2106,12 +2118,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Notificarea a fost mutată în jos la Silențioasă. Atingeți pentru a oferi feedback."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Notificarea a fost mutată la un nivel superior. Atingeți pentru a oferi feedback."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Notificarea a fost mutată la un nivel inferior. Atingeți pentru a oferi feedback."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Încercați notificările optimizate"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Ca să primiți în continuare acțiuni sugerate, răspunsuri și altele, activați notificările optimizate. Notificările adaptive Android nu mai sunt acceptate."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Activați"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Nu acum"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Aflați mai multe"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Notificările optimizate pot citi tot conținutul notificărilor, inclusiv informații cu caracter personal, precum mesajele și numele persoanelor de contact. În plus, funcția poate să închidă notificări sau să acționeze asupra butoanelor din notificări, inclusiv să răspundă la apeluri telefonice.\n\nÎn plus, funcția poate să activeze sau să dezactiveze modul Cu prioritate și să schimbe setările asociate."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificare pentru informații despre modul Rutină"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateria se poate descărca înainte de încărcarea obișnuită"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Economisirea bateriei este activată pentru a prelungi durata de funcționare a bateriei"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 7d87d7c..2e9c749 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1554,7 +1554,7 @@
</plurals>
<string name="action_mode_done" msgid="2536182504764803222">"Готово"</string>
<string name="progress_erasing" msgid="6891435992721028004">"Очистка единого хранилища…"</string>
- <string name="share" msgid="4157615043345227321">"Отправить"</string>
+ <string name="share" msgid="4157615043345227321">"Поделиться"</string>
<string name="find" msgid="5015737188624767706">"Найти"</string>
<string name="websearch" msgid="5624340204512793290">"Веб-поиск"</string>
<string name="find_next" msgid="5341217051549648153">"Cлед."</string>
@@ -1817,6 +1817,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1853,6 +1864,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kaku"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Неизвестный вертикальный формат"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Неизвестный горизонтальный формат"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Печать отменена"</string>
@@ -1898,8 +1910,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Обновлено администратором"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Удалено администратором"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"В режиме энергосбережения включается тёмная тема. Кроме того, отключаются или ограничиваются фоновые процессы, некоторые визуальные эффекты и различные функции, например распознавание команды \"Окей, Google\".\n\n"<annotation id="url">"Подробнее…"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"В режиме энергосбережения включается тёмная тема. Кроме того, отключаются или ограничиваются фоновые процессы, некоторые визуальные эффекты и различные функции, например распознавание команды \"Окей, Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"В режиме энергосбережения включается тёмная тема, ограничиваются или отключаются фоновые процессы, некоторые визуальные эффекты и определенные функции.\n\n"<annotation id="url">"Подробнее…"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"В режиме энергосбережения включается тёмная тема, ограничиваются или отключаются фоновые процессы, некоторые визуальные эффекты и определенные функции."</string>
<string name="data_saver_description" msgid="4995164271550590517">"В режиме экономии трафика фоновая передача данных для некоторых приложений отключена. Приложение, которым вы пользуетесь, может получать и отправлять данные, но реже, чем обычно. Например, изображения могут не загружаться, пока вы не нажмете на них."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Включить экономию трафика?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Включить"</string>
@@ -2120,7 +2132,7 @@
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ОТКРЫТЬ"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Обнаружено вредоносное приложение"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Приложение \"<xliff:g id="APP_0">%1$s</xliff:g>\" запрашивает разрешение на показ фрагментов приложения \"<xliff:g id="APP_2">%2$s</xliff:g>\"."</string>
- <string name="screenshot_edit" msgid="7408934887203689207">"Редактировать"</string>
+ <string name="screenshot_edit" msgid="7408934887203689207">"Изменить"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Для звонков и уведомлений включен вибросигнал."</string>
<string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Для звонков и уведомлений отключен звук."</string>
<string name="notification_channel_system_changes" msgid="2462010596920209678">"Системные изменения"</string>
@@ -2139,12 +2151,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Уровень важности этого уведомления был понижен до \"Без звука\". Нажмите, чтобы отправить отзыв."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Уровень важности этого уведомления был повышен. Нажмите, чтобы отправить отзыв."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Уровень важности этого уведомления был понижен. Нажмите, чтобы отправить отзыв."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Улучшенные уведомления"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Чтобы по-прежнему пользоваться рекомендуемыми действиями, ответами и другими подсказками, включите улучшенные уведомления. Адаптивные уведомления для Android больше не поддерживаются."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Включить"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Не сейчас"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Улучшенные уведомления"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Быстрые ответы и действия теперь включены в улучшенные уведомления. Адаптивные уведомления для Android больше не поддерживаются."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ОК"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Отключить"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Подробнее"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Улучшенным уведомлениям доступно содержимое всех уведомлений, в том числе личная информация, такая как имена контактов и сообщения. У этой функции также есть право закрывать уведомления и нажимать кнопки в них, например отвечать на звонки.\n\nКроме того, улучшенные уведомления могут включать и отключать режим \"Только важные\" и изменять связанные с ним настройки."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"В Android 12 адаптивные уведомления заменены улучшенными. Эта функция упорядочивает все ваши уведомления и подсказывает ответы и действия.\n\nЕй доступно содержимое всех уведомлений, в том числе личная информация, такая как имена контактов и сообщения. Также эта функция может закрывать уведомления и нажимать кнопки в них, например отвечать на звонки или управлять режимом \"Не беспокоить\"."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Уведомление о батарее"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батарея может разрядиться"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Чтобы увеличить время работы от батареи, был включен режим энергосбережения."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index c0577d6..e98c547 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"ෆුල්ස්කැප්"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super-B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"නොදන්නා සිරස් දිශානතිය"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"නොදන්නා තිරස් දිශානතිය"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"අවලංගු කරන ලදි"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ඔබගේ පරිපාලක මඟින් යාවත්කාලීන කර ඇත"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ඔබගේ පරිපාලක මඟින් මකා දමා ඇත"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"හරි"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"බැටරි සුරැකුම අඳුරු තේමාව ක්රියාත්මක කර පසුබිම් ක්රියාකාරකම්, සමහර දෘශ්ය ප්රයෝග සහ “Hey Google” වැනි විශේෂාංග සීමා කරයි\n\n"<annotation id="url">"තව දැන ගන්න"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"බැටරි සුරැකුම අඳුරු තේමාව ක්රියාත්මක කර පසුබිම් ක්රියාකාරකම්, සමහර දෘශ්ය ප්රයෝග සහ “Hey Google” වැනි විශේෂාංග සීමා කරයි."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"බැටරි සුරැකුම අඳුරු තේමාව ක්රියාත්මක කර පසුබිම් ක්රියාකාරකම්, සමහර දෘශ්ය ප්රයෝග සහ යම් විශේෂාංග ක්රියාවිරහිත හෝ සීමා කරයි.\n\n"<annotation id="url">"තව දැන ගන්න"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"බැටරි සුරැකුම අඳුරු තේමාව ක්රියාත්මක කර පසුබිම් ක්රියාකාරකම්, සමහර දෘශ්ය ප්රයෝග සහ යම් විශේෂාංග ක්රියාවිරහිත හෝ සීමා කරයි."</string>
<string name="data_saver_description" msgid="4995164271550590517">"දත්ත භාවිතය අඩු කිරීමට උදවු වීමට, දත්ත සුරැකුම සමහර යෙදුම් පසුබිමින් දත්ත යැවීම සහ ලබා ගැනීම වළක්වයි. ඔබ දැනට භාවිත කරන යෙදුමකට දත්ත වෙත පිවිසීමට හැකිය, නමුත් එසේ කරන්නේ කලාතුරකින් විය හැකිය. මෙයින් අදහස් වන්නේ, උදාහරණයක් ලෙස, එම රූප ඔබ ඒවාට තට්ටු කරන තෙක් සංදර්ශනය නොවන බවය."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"දත්ත සුරැකුම ක්රියාත්මක කරන්නද?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ක්රියාත්මක කරන්න"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"මෙම දැනුම්දීම නිහඬ වෙත පහත දමන ලදී. ප්රතිපෝෂණය ලබා දීමට තට්ටු කරන්න."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"මෙම දැනුම්දීම ඉහළට ශ්රේණිගත කරන ලදී. ප්රතිපෝෂණය ලබා දීමට තට්ටු කරන්න."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"මෙම දැනුම්දීම පහළට ශ්රේණිගත කරන ලදී. ප්රතිපෝෂණය ලබා දීමට තට්ටු කරන්න."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"දියුණු කළ දැනුම්දීම් උත්සාහ ක."</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"යෝජිත ක්රියා, පිළිතුරු සහ තවත් දේ ලබා ගැනීම සඳහා, වැඩි දියුණු කළ දැනුම්දීම් ක්රියාත්මක කරන්න. Android අනුවර්තී දැනුම්දීම් තවදුරටත් සහාය නොදක්වයි."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ක්රියාත්මක කරන්න"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"දැන් නොවේ"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"වැඩිදියුණු කළ දැනුම්දීම්"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"යෝජිත ක්රියා සහ පිළිතුරු දැන් වැඩි දියුණු කරන ලද දැනුම්දීම් මගින් සපයනු ලැබේ. Android අනුවර්තී දැනුම්දීම් තවදුරටත් සහාය නොදක්වයි."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"හරි"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ක්රියාවිරහිත කරන්න"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"තව දැන ගන්න"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"වැඩිදියුණු කළ දැනුම්දීම්වලට සම්බන්ධතා නම් සහ පණිවිඩ වැනි පුද්ගලික තොරතුරු ඇතුළුව, සියලු දැනුම්දීම් අන්තර්ගතය කියවිය හැකිය. මෙම විශේෂාංගයට දැනුම්දීම් ඉවත දැමීමට හෝ දුරකථන ඇමතුම්වලට පිළිතුරු දීම වැනි, දැනුම්දීම්වල බොත්තම් මත ක්රියා සිදු කිරීමටද හැකිය.\n\nමෙම විශේෂාංගයට ප්රමුඛතා ප්රකාරය ක්රියාත්මක හෝ ක්රියාවිරහිත කිරීමට සහ අදාළ සැකසීම් වෙනස් කිරීමටද හැකිය."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"වැඩිදියුණු කළ දැනුම්දීම් Android 12 හි Android අනුවර්තී දැනුම්දීම් ප්රතිස්ථාපනය කරයි. මෙම විශේෂාංගය යෝජිත ක්රියා සහ පිළිතුරු පෙන්වන අතර, ඔබගේ දැනුම්දීම් සංවිධානය කරයි.\n\nවැඩිදියුණු කළ දැනුම්දීම්වලට සම්බන්ධතා නම් සහ පණිවිඩ වැනි පුද්ගලික තොරතුරු ඇතුළුව, සියලු දැනුම්දීම් අන්තර්ගතය වෙත ප්රවේශ විය හැකිය. මෙම විශේෂාංගයට දැනුම්දීම් ඉවත දැමීමට හෝ දුරකථන ඇමතුම්වලට පිළිතුරු දීම සහ බාධා නොකරන්න පාලනය කිරීම වැනි, දැනුම්දීම්වලට ප්රතිචාර දැක්වීමටද හැකිය."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"දිනචරියා ප්රකාර තතු දැනුම්දීම"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"බැටරිය සුපුරුදු ආරෝපණයට පෙර ඉවර විය හැක"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"බැටරි සුරැකුම බැටරි ආයු කාලය දීර්ඝ කිරීමට සක්රිය කෙරිණි"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 5c9ddf7..6a68397 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -325,7 +325,7 @@
<string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"prístup k vašej fyzickej aktivite"</string>
<string name="permgrouplab_camera" msgid="9090413408963547706">"Fotoaparát"</string>
<string name="permgroupdesc_camera" msgid="7585150538459320326">"fotenie a natáčanie videí"</string>
- <string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"Zariadenia v okolí"</string>
+ <string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"Zariadenia nablízku"</string>
<string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"objavovať a pripájať zariadenia v okolí"</string>
<string name="permgrouplab_calllog" msgid="7926834372073550288">"Zoznam hovorov"</string>
<string name="permgroupdesc_calllog" msgid="2026996642917801803">"čítať a zapisovať do zoznamu hovorov"</string>
@@ -1753,7 +1753,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Použiť skratku"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzia farieb"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Úprava farieb"</string>
- <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Mimoriadne stmavenie"</string>
+ <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Veľmi tmavé"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pridržali ste tlačidlá hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Pridržali ste tlačidlá hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vypnutá."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Ak chcete používať službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, pridržte tri sekundy oba klávesy hlasitosti"</string>
@@ -1817,6 +1817,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1853,6 +1864,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Neznáma veľkosť papiera na výšku"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Neznáma veľkosť papiera na šírku"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Zrušené"</string>
@@ -1898,8 +1910,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizoval správca"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Odstránil správca"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Šetrič batérie zapne tmavý motív a obmedzí alebo vypne aktivitu na pozadí, niektoré vizuálne efekty a funkcie, napríklad „Hey Google“\n\n"<annotation id="url">"Ďalšie informácie"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Šetrič batérie zapne tmavý motív a obmedzí alebo vypne aktivitu na pozadí, niektoré vizuálne efekty a funkcie, napríklad „Hey Google“."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Šetrič batérie zapne tmavý motív a obmedzí alebo vypne aktivitu na pozadí, niektoré vizuálne efekty a určité funkcie.\n\n"<annotation id="url">"Ďalšie informácie"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Šetrič batérie zapne tmavý motív a obmedzí alebo vypne aktivitu na pozadí, niektoré vizuálne efekty a určité funkcie."</string>
<string name="data_saver_description" msgid="4995164271550590517">"S cieľom znížiť spotrebu dát bráni šetrič dát niektorým aplikáciám odosielať alebo prijímať dáta na pozadí. Aplikácia, ktorú práve používate, môže využívať dáta, ale možno to bude robiť menej často. Môže to napríklad znamenať, že sa obrázky zobrazia, až keď na ne klepnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Chcete zapnúť šetrič dát?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Zapnúť"</string>
@@ -2139,12 +2151,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Toto upozornenie bolo znížené na Tiché. Klepnutím nám poskytnite spätnú väzbu."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Toto upozornenie bolo preradené vyššie. Klepnutím nám poskytnite spätnú väzbu."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Toto upozornenie bolo preradené nižšie. Klepnutím nám poskytnite spätnú väzbu."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Skúste zlepšené upozornenia"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Ak chcete ďalej dostávať navrhované akcie, odpovede a ďalší obsah, zapnite zlepšené upozornenia. Adaptívne upozornenia Androidu už nie sú podporované."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Zapnúť"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Teraz nie"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Zlepšené upozornenia"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Navrhované akcie a odpovede budú odteraz poskytované zlepšenými upozorneniami. Adaptívne upozornenia Androidu už nie sú podporované."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Vypnúť"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Ďalšie informácie"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Zlepšené upozornenia môžu čítať všetok obsah upozornení vrátane osobných údajov, ako sú mená kontaktov a správy. Táto funkcia tiež môže rušiť upozornenia alebo aktivovať tlačidlá v upozorneniach, napríklad na prijatie telefonických hovorov.\n\nTáto funkcia môže tiež zapnúť alebo vypnúť režim priority a zmeniť súvisiace nastavenia."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Adaptívne upozornenia Androidu boli v Androide 12 nahradené zlepšenými upozorneniami. Táto funkcia zobrazuje navrhované akcie aj odpovede a organizuje vaše upozornenia.\n\nZlepšené upozornenia majú prístup k obsahu upozornení vrátane osobných údajov, ako sú mená kontaktov a správy. Táto funkcia tiež môže zavrieť upozornenia alebo na ne reagovať, napríklad prijať telefonáty a ovládať režim bez vyrušení."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Upozornenie s informáciami o rutinnom režime"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batéria sa môže vybiť pred obvyklým nabitím"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Bol aktivovaný šetrič batérie na predĺženie výdrže batérie"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index e98d0ae..5759f6ad 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1817,6 +1817,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1853,6 +1864,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Neznano pokončno"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Neznano ležeče"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Preklicano"</string>
@@ -1898,11 +1910,11 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Posodobil skrbnik"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisal skrbnik"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"V redu"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Varčevanje z energijo baterije vklopi temno temo in omeji ali izklopi dejavnost v ozadju, nekatere vizualne učinke in druge funkcije, kot je »Hey Google«.\n\n"<annotation id="url">"Več o tem"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Varčevanje z energijo baterije vklopi temno temo in omeji ali izklopi dejavnost v ozadju, nekatere vizualne učinke in druge funkcije, kot je »Hey Google«."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Varčevanje z energijo baterije vklopi temno temo ter omeji ali izklopi dejavnost v ozadju, nekatere vizualne učinke in določene funkcije.\n\n"<annotation id="url">"Več o tem"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Varčevanje z energijo baterije vklopi temno temo ter omeji ali izklopi dejavnost v ozadju, nekatere vizualne učinke in določene funkcije."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Zaradi zmanjševanja prenesene količine podatkov funkcija varčevanja s podatki nekaterim aplikacijam preprečuje, da bi v ozadju pošiljale ali prejemale podatke. Aplikacija, ki jo trenutno uporabljate, lahko prenaša podatke, vendar to morda počne manj pogosto. To na primer pomeni, da se slike ne prikažejo, dokler se jih ne dotaknete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vklop varčevanja s podatki?"</string>
- <string name="data_saver_enable_button" msgid="4399405762586419726">"Vklop"</string>
+ <string name="data_saver_enable_button" msgid="4399405762586419726">"Vklopi"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
<item quantity="one">%d minuto (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="two">%d minuti (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -2120,7 +2132,7 @@
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"VSEENO ODPRI"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Zaznana je bila škodljiva aplikacija"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi prikazati izreze aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
- <string name="screenshot_edit" msgid="7408934887203689207">"Urejanje"</string>
+ <string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Vibriranje bo vklopljeno za klice in obvestila"</string>
<string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Zvonjenje bo izklopljeno za klice in obvestila"</string>
<string name="notification_channel_system_changes" msgid="2462010596920209678">"Sistemske spremembe"</string>
@@ -2139,12 +2151,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"To obvestilo je bilo uvrščeno nižje – med obvestila brez zvoka. Dotaknite se, če želite poslati povratne informacije."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"To obvestilo je bilo uvrščeno višje. Dotaknite se, če želite poslati povratne informacije."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"To obvestilo je bilo uvrščeno nižje. Dotaknite se, če želite poslati povratne informacije."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Preizkusite pametna obvestila"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Če želite še naprej prejemati predlagana dejanja, odgovore in drugo, vklopite pametna obvestila. Prilagodljiva obvestila Android niso več podprta."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Vklopi"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ne zdaj"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Več o tem"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Pametna obvestila lahko preberejo vso vsebino obvestil, vključno z osebnimi podatki, kot so imena in sporočila stikov. Ta funkcija lahko tudi opusti obvestila in izvaja dejanja z gumbi v obvestilih, kot je sprejemanje telefonskih klicev.\n\nPoleg tega lahko ta funkcija vklopi ali izklopi prednostni način ter spremeni povezane nastavitve."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutinsko informativno obvestilo o načinu delovanja"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterija se bo morda izpraznila, preden jo običajno priključite na polnjenje"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Vklopilo se je varčevanje z energijo baterije za podaljšanje časa delovanja baterije"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 30e13a4..3f0b8f3 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"\"Monarch\""</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"\"Quatro\""</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,8 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <!-- no translation found for mediasize_japanese_l (1326765321473431817) -->
+ <skip />
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Vertikalisht i panjohur"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Orientim i panjohur horizontal"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Anuluar"</string>
@@ -1852,8 +1865,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Përditësuar nga administratori"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Fshirë nga administratori"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Në rregull"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"\"Kursyesi i baterisë\" aktivizon \"Temën e errët\" dhe kufizon ose çaktivizon aktivitetin në sfond, disa efekte vizuale dhe veçoritë si \"Ok Google\"\n\n"<annotation id="url">"Mëso më shumë"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"\"Kursyesi i baterisë\" aktivizon \"Temën e errët\" dhe kufizon ose çaktivizon aktivitetin në sfond, disa efekte vizuale dhe veçoritë si \"Ok Google\"."</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (5693741424234005958) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"Për të ndihmuar në reduktimin e përdorimit të të dhënave, \"Kursyesi i të dhënave\" pengon që disa aplikacione të dërgojnë apo të marrin të dhëna në sfond. Një aplikacion që po përdor aktualisht mund të ketë qasje te të dhënat, por këtë mund ta bëjë më rrallë. Kjo mund të nënkuptojë, për shembull, se imazhet nuk shfaqen kur troket mbi to."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Të aktivizohet \"Kursyesi i të dhënave\"?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivizo"</string>
@@ -2073,12 +2088,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Ky njoftim është ulur në nivel si në heshtje. Trokit për të dhënë komente."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Ky njoftim është renditur më lart. Trokit për të dhënë komente."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Ky njoftim është renditur më poshtë. Trokit për të dhënë komente."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Provo njoftimet e përmirësuara"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Për të vazhduar të marrësh sugjerime për veprimet, përgjigjet etj., aktivizo njoftimet e përmirësuara. \"Njoftimet me përshtatje të Android\" nuk mbështeten më."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aktivizo"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Jo tani"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Mëso më shumë"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Njoftimet e përmirësuara mund të lexojnë të gjithë përmbajtjen e njoftimeve, duke përfshirë edhe informacionet personale si emrat e kontakteve dhe mesazhet. Kjo veçori mund të heqë po ashtu njoftimet ose të veprojë mbi butonat te njoftimet, si p.sh. t\'u përgjigjet telefonatave.\n\nKjo veçori mund të aktivizojë ose të çaktivizojë po ashtu modalitetin \"Me përparësi\" dhe të ndryshojë cilësimet përkatëse."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Njoftimi i informacionit të \"Modalitetit rutinë\""</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateria mund të mbarojë përpara ngarkimit të zakonshëm"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"\"Kursyesi i baterisë\" u aktivizua për të rritur kohëzgjatjen e baterisë"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 96fa82d..e4cadb7 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1795,6 +1795,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1831,6 +1842,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Непозната величина, усправно"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Непозната величина, водоравно"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Отказано је"</string>
@@ -1875,8 +1887,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирао је администратор"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Избрисао је администратор"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Потврди"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Уштеда батерије укључује Тамну тему и ограничава или искључује активности у позадини, неке визуелне ефекте и функције, на пример, „Хеј Google“.\n\n"<annotation id="url">"Сазнајте више"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Уштеда батерије укључује Тамну тему и ограничава или искључује активности у позадини, неке визуелне ефекте и функције, на пример, „Хеј Google“."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Уштеда батерије укључује Тамну тему и ограничава или искључује активности у позадини, неке визуелне ефекте и одређене функције.\n\n"<annotation id="url">"Сазнајте више"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Уштеда батерије укључује Тамну тему и ограничава или искључује активности у позадини, неке визуелне ефекте и одређене функције."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Да би се смањила потрошња података, Уштеда података спречава неке апликације да шаљу или примају податке у позадини. Апликација коју тренутно користите може да приступа подацима, али ће то чинити ређе. На пример, слике се неће приказивати док их не додирнете."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Желите да укључите Уштеду података?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Укључи"</string>
@@ -2106,12 +2118,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Ово обавештење је деградирано у Нечујно. Додирните да бисте навели повратне информације."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Ово обавештење је рангирано више. Додирните да бисте навели повратне информације."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Ово обавештење је рангирано ниже. Додирните да бисте навели повратне информације."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Пробајте побољшана обавештења"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Укључите побољшана обавештења да бисте и даље добијали препоручене радње, одговоре и друго. Прилагодљива обавештења за Android више нису подржана."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Укључи"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Не сада"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Побољшана обавештења"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Предложене радње и одговоре сада добијате помоћу побољшаних обавештења. Прилагодљива обавештења за Android више нису подржана."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Потврди"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Искључи"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Сазнајте више"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Побољшана обавештења могу да читају садржај свих обавештења, укључујући личне податке, попут имена контаката и порука. Ова функција може и да одбацује обавештења или активира дугмад у обавештењима, попут јављања на телефонске позиве.\n\nОва функција може и да укључи или искључи Приоритетни режим и да мења повезана подешавања."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Побољшана обавештења су заменила Android прилагодљива обавештења у Android-у 12. Ова функција показује предложене радње и одговоре и организује обавештења.\n\nПобољшана обавештења могу да приступају садржају обавештења, укључујући личне информације попут имена контаката и порука. Ова функција може и да одбацује обавештења или да одговара на њих, на пример, да се јавља на телефонске позиве и контролише режим Не узнемиравај."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Обавештење о информацијама Рутинског режима"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батерија ће се можда испразнити пре уобичајеног пуњења"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Уштеда батерије је активирана да би се продужило трајање батерије"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 0ddf34d..e07cf41 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Porträtt – okänd storlek"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Landskap – okänd storlek"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Inställd"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administratören uppdaterade paketet"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratören raderade paketet"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"I batterisparläget aktiveras mörkt tema och bakgrundsaktivitet som vissa visuella effekter och funktioner som ”Hey Google” begränsas eller inaktiveras\n\n"<annotation id="url">"Läs mer"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"I batterisparläget aktiveras mörkt tema och bakgrundsaktivitet som vissa visuella effekter och funktioner som ”Hey Google” begränsas eller inaktiveras."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Batterisparläget aktiverar mörkt tema och begränsar eller inaktiverar bakgrundsaktivitet, vissa visuella effekter och vissa funktioner.\n\n"<annotation id="url">"Läs mer"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Batterisparläget aktiverar mörkt tema och begränsar eller inaktiverar bakgrundsaktivitet, vissa visuella effekter och vissa funktioner."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Med Databesparing kan du minska dataanvändningen genom att hindra en del appar från att skicka eller ta emot data i bakgrunden. Appar som du använder kan komma åt data, men det sker kanske inte lika ofta. Detta innebär t.ex. att bilder inte visas förrän du trycker på dem."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vill du aktivera Databesparing?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivera"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Den här aviseringen har ändrats till Tyst. Tryck för att lämna feedback."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Den här aviseringen har fått högre rankning. Tryck för att lämna feedback."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Den här aviseringen har fått lägre rankning. Tryck för att lämna feedback."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Testa förbättrade aviseringar"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Aktivera förbättrade aviseringar om du vill fortsätta att få rekommenderade åtgärder, svar och annat. Anpassade aviseringar för Android stöds inte längre."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aktivera"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Inte nu"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Förbättrade aviseringar"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Förslag på åtgärder och svar tillhandahålls nu via förbättrade aviseringar. Anpassade aviseringar för Android stöds inte längre."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Inaktivera"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Läs mer"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Förbättrade aviseringar kan läsa allt innehåll i aviseringar, inklusive personliga uppgifter som namn på kontakter och meddelanden. Funktionen kan även stänga aviseringar eller använda åtgärdsknappar i aviseringar, till exempel för att svara på telefonsamtal.\n\nFunktionen kan även aktivera och inaktivera prioritetsläget och ändra tillhörande inställningar."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Förbättrade aviseringar har ersatt Anpassade aviseringar för Android i Android 12. Den här funktionen visar förslag på åtgärder och svar och organiserar dina aviseringar.\n\nFörbättrade aviseringar har åtkomst till allt innehåll i aviseringar, inklusive personliga uppgifter som namn på kontakter och meddelanden. Funktionen kan även ignorera aviseringar eller utföra åtgärder utifrån dem, till exempel svara på telefonsamtal och styra Stör ej."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Avisering om rutinläge"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batteriet kan ta slut innan du brukar ladda det"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterisparläget har aktiverats för att utöka batteritiden"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index ea069e1..c2e14bb 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Mkao wima usiojulikana"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Mandhari yasiyojulikana"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Imeghairiwa"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Imesasishwa na msimamizi wako"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Imefutwa na msimamizi wako"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Sawa"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Kiokoa Betri huwasha Mandhari meusi na kudhibiti au kuzima shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele kama vile \"Ok Google\"\n\n"<annotation id="url">"Pata maelezo zaidi"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Kiokoa Betri huwasha Mandhari meusi na kudhibiti au kuzima shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele kama vile \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Kiokoa Betri huwasha Mandhari meusi na kudhibiti au kuzima shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele fulani.\n\n"<annotation id="url">"Pata maelezo zaidi"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Kiokoa Betri huwasha Mandhari meusi na kudhibiti au kuzima shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele fulani."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Ili kusaidia kupunguza matumizi ya data, Kiokoa Data huzuia baadhi ya programu kupokea na kutuma data chinichini. Programu ambayo unatumia sasa inaweza kufikia data, lakini si kila wakati. Kwa mfano, haitaonyesha picha hadi utakapozifungua."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ungependa Kuwasha Kiokoa Data?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Washa"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Arifa hii ilishushwa hadhi kuwa Kimya. Gusa ili utoe maoni."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Arifa hii imeorodheshwa katika nafasi ya juu. Gusa ili utoe maoni."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Arifa hii imeorodheshwa katika nafasi ya chini. Gusa ili utoe maoni."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Jaribu arifa zilizoboreshwa"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Ili uendelee kupata vitendo, majibu na mambo mengine yanayopendekezwa, washa arifa zilizoboreshwa. Arifa Zinazojirekebisha za Android hazitumiki tena."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Washa"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Si sasa"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Pata maelezo zaidi"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Kipengele cha Arifa zilizoboreshwa kinaweza kusoma maudhui yote ya arifa, zikiwemo taarifa binafsi kama vile majina ya anwani na ujumbe. Kipengele hiki kinaweza pia kuondoa arifa au kuchukua hatua kwenye vitufe katika arifa, kama vile kujibu simu.\n\nKipengele hiki pia kinaweza kuwasha au kuzima hali ya Kipaumbele na kubadilisha mipangilio inayohusiana."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Arifa ya maelezo ya Hali ya Kawaida"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Huenda betri itakwisha chaji mapema"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Imewasha Kiokoa Betri ili kurefusha muda wa matumizi ya betri"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 962b9a3..23cab42 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1707,8 +1707,8 @@
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"முடிந்தது"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ஷார்ட்கட்டை முடக்கு"</string>
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ஷார்ட்கட்டைப் பயன்படுத்து"</string>
- <string name="color_inversion_feature_name" msgid="326050048927789012">"கலர் இன்வெர்ஷன்"</string>
- <string name="color_correction_feature_name" msgid="3655077237805422597">"வண்ணத் திருத்தம்"</string>
+ <string name="color_inversion_feature_name" msgid="326050048927789012">"நிற நேரெதிர் மாற்றம்"</string>
+ <string name="color_correction_feature_name" msgid="3655077237805422597">"நிறத் திருத்தம்"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"மிகக் குறைவான வெளிச்சம்"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆன் செய்யப்பட்டது."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆஃப் செய்யப்பட்டது."</string>
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"மோனார்க்"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"குவார்டோ"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"பூல்ஸ்கேப்"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"அறியப்படாத நிலைபதிப்பு"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"அறியப்படாத நிலைபரப்பு"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ரத்துசெய்யப்பட்டது"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"உங்கள் நிர்வாகி நீக்கியுள்ளார்"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"சரி"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"பேட்டரி சேமிப்பான் டார்க் தீமினை ஆன் செய்து பின்னணிச் செயல்பாடு, சில விஷுவல் எஃபெக்ட்கள், “Ok Google” போன்ற அம்சங்களை ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்\n\n"<annotation id="url">"மேலும் அறிக"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"பேட்டரி சேமிப்பான் டார்க் தீமினை ஆன் செய்து பின்னணிச் செயல்பாடு, சில விஷுவல் எஃபெக்ட்கள், “Ok Google” போன்ற அம்சங்களை ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"பேட்டரி சேமிப்பான் டார்க் தீமை ஆன் செய்யும். பின்னணிச் செயல்பாடு, சில விஷுவல் எஃபெக்ட்கள் மற்றும் குறிப்பிட்ட அம்சங்களைக் கட்டுப்படுத்தும் அல்லது ஆஃப் செய்யும்.\n\n"<annotation id="url">"மேலும் அறிக"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"பேட்டரி சேமிப்பான் டார்க் தீமை ஆன் செய்யும். பின்னணிச் செயல்பாடு, சில விஷுவல் எஃபெக்ட்கள் மற்றும் குறிப்பிட்ட அம்சங்களைக் கட்டுப்படுத்தும் அல்லது ஆஃப் செய்யும்."</string>
<string name="data_saver_description" msgid="4995164271550590517">"டேட்டா உபயோகத்தைக் குறைப்பதற்கு உதவ, பின்புலத்தில் டேட்டாவை அனுப்புவது அல்லது பெறுவதிலிருந்து சில ஆப்ஸை டேட்டா சேமிப்பான் தடுக்கும். தற்போது பயன்படுத்தும் ஆப்ஸானது எப்போதாவது டேட்டாவை அணுகலாம். எடுத்துக்காட்டாக, படங்களை நீங்கள் தட்டும் வரை அவை காட்டப்படாது."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"டேட்டா சேமிப்பானை இயக்கவா?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"இயக்கு"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"இந்த அறிவிப்பின் முக்கியத்துவம் நிசப்த நிலைக்குக் குறைத்து அமைக்கப்பட்டது. கருத்து தெரிவிக்க தட்டவும்."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"இந்த அறிவிப்பின் முக்கியத்துவம் உயர்த்தப்பட்டது. கருத்து தெரிவிக்க தட்டவும்."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"இந்த அறிவிப்பின் முக்கியத்துவம் குறைக்கப்பட்டது. கருத்து தெரிவிக்க தட்டவும்."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"மேம்பட்ட அறிவிப்புகளை முயல்க"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"பரிந்துரைக்கப்பட்ட செயல்பாடுகள், பதில்கள் மற்றும் பலவற்றையும் தொடர்ந்து பெற மேம்பட்ட அறிவிப்புகளை ஆன் செய்யவும். Android சூழலுக்கேற்ற அறிவிப்புகள் இனி ஆதரிக்கப்படாது."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ஆன் செய்"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"இப்போது வேண்டாம்"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"மேலும் அறிக"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"மேம்பட்ட அறிவிப்புகளால் அனைத்து அறிவிப்புகளின் உள்ளடக்கத்தையும் (தொடர்புகளின் பெயர்கள், மெசேஜ்கள் போன்ற தனிப்பட்ட தகவல்கள் உட்பட) படிக்க முடியும். இந்த அம்சத்தால் அறிவிப்புகளை நிராகரிக்கவோ அறிவிப்புகளிலுள்ள பட்டன்களை இயக்கவோ (அழைப்புகளுக்குப் பதிலளிப்பது போன்றவை) முடியும்.\n\nஇந்த அம்சத்தால் முன்னுரிமைப் பயன்முறையை இயக்கவோ முடக்கவோ முடியும் மற்றும் தொடர்புடைய அமைப்புகளை மாற்றவும் முடியும்."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"வழக்கமான பேட்டரி சேமிப்பானுக்கான விவர அறிவிப்பு"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"வழக்கமாகச் சார்ஜ் செய்வதற்கு முன்பே பேட்டரி தீர்ந்துபோகக்கூடும்"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"பேட்டரி நிலையை நீட்டிக்க பேட்டரி சேமிப்பான் இயக்கப்பட்டுள்ளது"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 2fa3710..aa97fb5 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"మోనార్క్"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"క్వార్టో"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"ఫుల్స్కేప్"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,8 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"కాహు"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"కాకు2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"యు4"</string>
+ <!-- no translation found for mediasize_japanese_l (1326765321473431817) -->
+ <skip />
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"తెలియని పొర్ట్రెయిట్"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"తెలియని ల్యాండ్స్కేప్"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"రద్దు చేయబడింది"</string>
@@ -1852,8 +1865,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"మీ నిర్వాహకులు నవీకరించారు"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"మీ నిర్వాహకులు తొలగించారు"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"సరే"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"బ్యాటరీ సేవర్ ముదురు రంగు రూపంను ఆన్ చేస్తుంది అలాగే బ్యాక్గ్రౌండ్ యాక్టివిటీని, కొన్ని విజువల్ ఎఫెక్ట్లు, అలాగే “Ok Google” వంటి ఫీచర్లను పరిమితం చేస్తుంది లేదా ఆఫ్ చేస్తుంది\n\n"<annotation id="url">"మరింత తెలుసుకోండి"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"బ్యాటరీ సేవర్ ముదురు రంగు రూపంను ఆన్ చేస్తుంది అలాగే బ్యాక్గ్రౌండ్ యాక్టివిటీని, కొన్ని విజువల్ ఎఫెక్ట్లు, అలాగే “Ok Google” వంటి ఫీచర్లను పరిమితం చేస్తుంది లేదా ఆఫ్ చేస్తుంది."</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (5693741424234005958) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"డేటా వినియోగాన్ని తగ్గించడంలో డేటా సేవర్ సహాయకరంగా ఉంటుంది. బ్యాక్గ్రౌండ్లో కొన్ని యాప్లు డేటాను పంపకుండా లేదా స్వీకరించకుండా నిరోధిస్తుంది. మీరు ప్రస్తుతం ఉపయోగిస్తోన్న యాప్, డేటాను యాక్సెస్ చేయగలదు. కానీ తక్కువ సార్లు మాత్రమే అలా చేయవచ్చు. ఉదాహరణకు, మీరు నొక్కే వరకు ఫోటోలు ప్రదర్శించబడవు."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"డేటా సేవర్ను ఆన్ చేయాలా?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ఆన్ చేయి"</string>
@@ -2073,12 +2088,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ఈ నోటిఫికేషన్ స్థాయి నిశ్శబ్దంగా ఉండేలా తగ్గించబడింది. ఫీడ్బ్యాక్ను అందించడానికి ట్యాప్ చేయండి."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ఈ నోటిఫికేషన్కు ఎక్కువ ర్యాంక్ ఇవ్వబడింది. ఫీడ్బ్యాక్ను అందించడానికి ట్యాప్ చేయండి."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ఈ నోటిఫికేషన్కు తక్కువ ర్యాంక్ ఇవ్వబడింది. ఫీడ్బ్యాక్ను అందించడానికి ట్యాప్ చేయండి."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"మెరుగైన నోటిఫికేషన్ల ట్రై"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"సూచించిన చర్యలు, రిప్లయిలు, అలాగే మరిన్ని పొందడం కొనసాగించడానికి మెరుగైన నోటిఫికేషన్లను ఆన్ చేయండి. Android అనుకూల నోటిఫికేషన్లు ఇకపై సపోర్ట్ చేయవు."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ఆన్ చేయి"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ఇప్పుడు కాదు"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"మరింత తెలుసుకోండి"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"కాంటాక్ట్ పేర్లు, మెసేజ్లు వంటి వ్యక్తిగత సమాచారంతో సహా మెరుగైన నోటిఫికేషన్లు అన్ని నోటిఫికేషన్ కంటెంట్ను చదవగలవు. ఈ ఫీచర్ నోటిఫికేషన్లను తీసివేయవచ్చు లేదా ఫోన్ కాల్లకు సమాధానం ఇవ్వడం వంటి నోటిఫికేషన్లలోని బటన్లపై చర్యలు తీసుకోవచ్చు.\n\nఈ ఫీచర్ ప్రాధాన్యత మోడ్ను కూడా ఆన్ లేదా ఆఫ్ చేయవచ్చు, ఇది సంబంధిత సెట్టింగ్లను మార్చగలదు."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"రొటీన్ మోడ్ సమాచార నోటిఫికేషన్"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"మామూలుగా ఛార్జ్ చేసేలోపు బ్యాటరీ ఖాళీ కావచ్చు"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"బ్యాటరీ జీవితకాలాన్ని పెంచడానికి బ్యాటరీ సేవర్ యాక్టివేట్ చేయబడింది"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index db38765..65a38db 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"กระดาษฟุลสแก๊ป"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super-B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"แนวตั้งไม่ทราบขนาด"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"แนวนอนไม่ทราบขนาด"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ยกเลิก"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"อัปเดตโดยผู้ดูแลระบบ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ลบโดยผู้ดูแลระบบ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ตกลง"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"โหมดประหยัดแบตเตอรี่จะเปิดธีมมืดและจำกัดหรือปิดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อย่างเช่น \"Ok Google\"\n\n"<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"โหมดประหยัดแบตเตอรี่จะเปิดธีมมืดและจำกัดหรือปิดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อย่างเช่น \"Ok Google\""</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"โหมดประหยัดแบตเตอรี่จะเปิดใช้ธีมมืดและจำกัดหรือปิดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์บางส่วน\n\n"<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"โหมดประหยัดแบตเตอรี่จะเปิดใช้ธีมมืดและจำกัดหรือปิดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์บางส่วน"</string>
<string name="data_saver_description" msgid="4995164271550590517">"เพื่อช่วยลดปริมาณการใช้อินเทอร์เน็ต โปรแกรมประหยัดอินเทอร์เน็ตจะช่วยป้องกันไม่ให้บางแอปส่งหรือรับข้อมูลโดยการใช้อินเทอร์เน็ตอยู่เบื้องหลัง แอปที่คุณกำลังใช้งานสามารถเข้าถึงอินเทอร์เน็ตได้ แต่อาจไม่บ่อยเท่าเดิม ตัวอย่างเช่น ภาพต่างๆ จะไม่แสดงจนกว่าคุณจะแตะที่ภาพเหล่านั้น"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"เปิดการประหยัดอินเทอร์เน็ตไหม"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"เปิด"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"การแจ้งเตือนนี้มีการลดระดับเป็นแบบปิดเสียง แตะเพื่อแสดงความคิดเห็น"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"การแจ้งเตือนนี้มีการเพิ่มระดับ แตะเพื่อแสดงความคิดเห็น"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"การแจ้งเตือนนี้มีการลดระดับ แตะเพื่อแสดงความคิดเห็น"</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"ลองใช้การแจ้งเตือนที่เพิ่มประสิทธิภาพ"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"หากต้องการรับการดําเนินการ การตอบ และอื่นๆ ที่แนะนําต่อไป ให้เปิดการแจ้งเตือนที่เพิ่มประสิทธิภาพ ไม่รองรับการแจ้งเตือนแบบปรับอัตโนมัติใน Android อีกต่อไป"</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"เปิด"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ไว้ทีหลัง"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ดูข้อมูลเพิ่มเติม"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"การแจ้งเตือนที่เพิ่มประสิทธิภาพจะอ่านเนื้อหาการแจ้งเตือนทั้งหมดได้ รวมถึงข้อมูลส่วนบุคคล เช่น ชื่อผู้ติดต่อและข้อความ ฟีเจอร์นี้ยังปิดการแจ้งเตือนหรือดำเนินการกับปุ่มต่างๆ ในการแจ้งเตือนได้ด้วย เช่น การรับสายเรียกเข้า\n\nอีกทั้งสามารถเปิดหรือปิดโหมดลำดับความสำคัญสูงและเปลี่ยนแปลงการตั้งค่าที่เกี่ยวข้อง"</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"การแจ้งเตือนข้อมูลโหมดกิจวัตร"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"แบตเตอรี่อาจหมดก่อนการชาร์จปกติ"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"เปิดใช้งานโหมดประหยัดแบตเตอรี่แล้วเพื่อยืดอายุการใช้งานแบตเตอรี่"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index adaa774..c646cba 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Hindi alam na portrait"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Hindi alam na landscape"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Kinansela"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Na-update ng iyong admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Na-delete ng iyong admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Ino-on ng Pantipid ng Baterya ang Madilim na tema at nililimitahan o ino-off nito ang aktibidad sa background, ilang visual effect, at mga feature gaya ng “Hey Google”\n\n"<annotation id="url">"Matuto pa"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Ino-on ng Pantipid ng Baterya ang Madilim na tema at nililimitahan o ino-off nito ang aktibidad sa background, ilang visual effect, at mga feature gaya ng “Hey Google.”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Ino-on ng Pantipid ng Baterya ang Madilim na tema at nililimitahan o ino-off nito ang aktibidad sa background, ilang visual effect, at ilang partikular na feature.\n\n"<annotation id="url">"Matuto pa"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Ino-on ng Pantipid ng Baterya ang Madilim na tema at nililimitahan o ino-off nito ang aktibidad sa background, ilang visual effect, at ilang partikular na feature."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Upang makatulong na mabawasan ang paggamit ng data, pinipigilan ng Data Saver ang ilang app na magpadala o makatanggap ng data sa background. Maaaring mag-access ng data ang isang app na ginagamit mo sa kasalukuyan, ngunit mas bihira na nito magagawa iyon. Halimbawa, maaaring hindi lumabas ang mga larawan hangga\'t hindi mo nata-tap ang mga ito."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"I-on ang Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"I-on"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Na-demote sa Naka-silent ang notification na ito. I-tap para magbigay ng feedback."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Itinaas ang ranggo ng notification na ito. I-tap para magbigay ng feedback."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Ibinaba ang ranggo ng notification na ito. I-tap para magbigay ng feedback."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Subukan ang enhanced notification"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Para patuloy na makakuha ng mga iminumungkahing pagkilos, sagot, at higit pa, i-on ang mga pinahusay na notification. Hindi na sinusuportahan ang Mga Adaptive na Notification ng Android."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"I-on"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Hindi ngayon"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Mga pinahusay na notification"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Nagbibigay na ng mga iminumungkahing pagkilos at tugon ang mga pinahusay na notification. Hindi na sinusuportahan ang Mga Adaptive na Notification ng Android."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"I-off"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Matuto pa"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Puwedeng basahin ng mga pinahusay na notification ang lahat ng notification, kabilang ang personal na impormasyon gaya ng mga pangalan ng contact at mga mensahe. Magagawa ring ng feature na ito na i-dismiss ang mga notification o gumawa ng mga pagkilos sa mga button sa mga notification, gaya ng pagsagot sa mga tawag sa telepono.\n\nPuwede ring i-on o i-off ng feature na ito ang Priority mode at baguhin ang mga kaugnay na setting."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Pinalitan ng mga pinahusay na notification ang Mga Adaptive na Notification ng Android sa Android 12. Nagpapakita ng mga iminumungkahing pagkilos at tugon ang feature na ito, at isinasaayos nito ang iyong mga notification.\n\nMaa-access ng mga pinahusay na notification ang content ng notification, kabilang ang personal na impormasyon gaya ng mga pangalan ng contact at mensahe. Puwede ring i-dismiss o tugunan ng feature na ito ang mga notification, gaya ng pagsagot sa mga tawag at pagkontrol sa Huwag Istorbohin."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notification ng impormasyon ng Routine Mode"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Maaaring maubos ang baterya bago ang karaniwang pag-charge"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Na-activate ang Pantipid ng Baterya para patagalin ang buhay ng baterya"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index bd85322..668ae77 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Bilinmeyen dikey"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Bilinmeyen yatay"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"İptal edildi"</string>
@@ -1852,9 +1864,9 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Yöneticiniz tarafından güncellendi"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Yöneticiniz tarafından silindi"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Tamam"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Pil Tasarrufu, Koyu temayı açıp arka plan etkinliğini, bazı görsel efektleri ve \"Ok Google\" gibi özellikleri kapatır veya kısıtlar.\n\n"<annotation id="url">"Daha fazla bilgi"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Pil Tasarrufu, Koyu temayı açıp arka plan etkinliğini, bazı görsel efektleri ve \"Ok Google\" gibi özellikleri kapatır veya kısıtlar."</string>
- <string name="data_saver_description" msgid="4995164271550590517">"Veri kullanımını azaltmaya yardımcı olması için Veri Tasarrufu, bazı uygulamaların arka planda veri göndermesini veya almasını engeller. Şu anda kullandığınız bir uygulama veri bağlantısına erişebilir, ancak bunu daha seyrek yapabilir. Bu durumda örneğin, siz resimlere dokunmadan resimler görüntülenmez."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Pil Tasarrufu özelliği Koyu temayı açıp arka plan etkinliğini, bazı görsel efektleri ve belirli özellikleri sınırlandırır ya da kapatır.\n\n"<annotation id="url">"Daha fazla bilgi"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Pil Tasarrufu özelliği Koyu temayı açıp arka plan etkinliğini, bazı görsel efektleri ve belirli özellikleri sınırlandırır ya da kapatır."</string>
+ <string name="data_saver_description" msgid="4995164271550590517">"Veri kullanımını azaltmaya yardımcı olması için Veri Tasarrufu, bazı uygulamaların arka planda veri göndermesini veya almasını engeller. Kullanmakta olduğunuz bir uygulama veri bağlantısına erişebilir, ancak bunu daha seyrek yapabilir. Bu durumda örneğin, siz resimlere dokunmadan resimler görüntülenmez."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Veri Tasarrufu açılsın mı?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aç"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Bu bildirimin önem derecesi, \"Sessiz\" seviyesine düşürüldü. Geri bildirimde bulunmak için dokunun."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Bu bildirimin önem derecesi yükseltildi. Geri bildirimde bulunmak için dokunun."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Bu bildirimin önem derecesi düşürüldü. Geri bildirimde bulunmak için dokunun."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Gelişmiş bildirimleri deneyin"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Önerilen işlemleri, yanıtları ve diğer içerikleri almaya devam etmek için gelişmiş bildirimleri açın. Android Uyarlamalı Bildirimler artık desteklenmiyor."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aç"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Şimdi değil"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Gelişmiş bildirimler"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Önerilen işlemler ve yanıtlar artık gelişmiş bildirimler tarafından sağlanıyor. Android Uyarlamalı Bildirimler artık desteklenmiyor."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Tamam"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Kapat"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Daha fazla bilgi"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Gelişmiş bildirimler, kişiler ve mesajlar gibi kişisel bilgiler dahil olmak üzere tüm bildirim içeriklerini okuyabilir. Bu özellik ayrıca bildirimleri kapatabilir veya bildirimlerdeki düğmeler üzerinde telefon çağrılarını yanıtlamak gibi işlemler yapabilir.\n\nBu özellik ayrıca Öncelik modunu açıp kapatabilir ve ilgili ayarları değiştirebilir."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Gelişmiş bildirimler, Android 12\'de Android Uyarlamalı Bildirimler\'in yerini aldı. Bu özellik, önerilen işlem ve yanıtları gösterir ve bildirimlerinizi organize eder.\n\nGelişmiş bildirimler, kişiler ve mesajlar gibi kişisel bilgiler dahil olmak üzere tüm bildirim içeriklerine erişebilir. Bu özellik ayrıca bildirimleri kapatabilir veya telefon aramalarını yanıtlamak ve Rahatsız Etmeyin modunu kontrol etmek gibi işlemlerle bildirimlere yanıt verebilir."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutin Modu bilgi bildirimi"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Pil normal şarjdan önce bitebilir"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Pilin ömrünü uzatmak için Pil Tasarrufu etkinleştirildi"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index b95aa88..1eea6317f 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1817,6 +1817,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch (Пн. Америка)"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto (Пн. Америка)"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap (Пн. Америка)"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K (Китай)"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K (Китай)"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1 (Китай)"</string>
@@ -1853,6 +1864,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu (Японія)"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2 (Японія)"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4 (Японія)"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Невідома книжкова орієнтація"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Невідома альбомна орієнтація"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Скасовано"</string>
@@ -1898,8 +1910,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Оновлено адміністратором"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Видалено адміністратором"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"У режимі енергозбереження вмикається темна тема й обмежуються чи вимикаються фонова робота додатків, деякі візуальні ефекти та інші функції, як-от \"Ok Google\"\n\n"<annotation id="url">"Докладніше"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"У режимі енергозбереження вмикається темна тема й обмежуються чи вимикаються фонова робота додатків, деякі візуальні ефекти та інші функції, як-от \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"У режимі енергозбереження вмикається темна тема й обмежуються чи вимикаються фонова робота додатків, деякі візуальні ефекти та певні функції.\n\n"<annotation id="url">"Докладніше"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"У режимі енергозбереження вмикається темна тему й обмежуються чи вимикаються фонова робота додатків, деякі візуальні ефекти та певні функції."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Щоб зменшити використання трафіку, функція \"Заощадження трафіку\" не дозволяє деяким додаткам надсилати чи отримувати дані у фоновому режимі. Поточний додаток зможе отримувати доступ до таких даних, але рідше. Наприклад, зображення не відображатиметься, доки ви не торкнетеся його."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Увімкнути заощадження трафіку?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Увімкнути"</string>
@@ -2139,12 +2151,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Важливість цього сповіщення знижено до рівня \"Без звуку\". Натисніть, щоб надіслати відгук."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Важливість цього сповіщення підвищено. Натисніть, щоб надіслати відгук."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Важливість цього сповіщення знижено. Натисніть, щоб надіслати відгук."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Спробуйте покращені сповіщення"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Щоб і надалі отримувати пропозиції дій, відповідей тощо, увімкніть покращені сповіщення. Адаптивні сповіщення Android більше не підтримуються."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Увімкнути"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Не зараз"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Докладніше"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Покращені сповіщення дають змогу читати весь вміст сповіщень, зокрема особисту інформацію, як-от імена контактів і повідомлення. Крім того, ви зможете відхиляти сповіщення або натискати кнопки в них, щоб виконувати певні дії, наприклад відповідати на телефонні дзвінки.\n\nЦя функція також дає змогу вмикати й вимикати режим пріоритетності та змінювати відповідні налаштування."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Сповіщення про послідовнсть дій"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Акумулятор може розрядитися раніше ніж зазвичай"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Режим енергозбереження активовано для збільшення часу роботи акумулятора"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index f067641b..1f056fa 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"مونارک"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"کوارٹو"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"فل اسکیپ"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,8 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <!-- no translation found for mediasize_japanese_l (1326765321473431817) -->
+ <skip />
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"نامعلوم پورٹریٹ"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"نامعلوم لینڈ اسکیپ"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"منسوخ کر دیا گیا"</string>
@@ -1852,8 +1865,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"آپ کے منتظم کے ذریعے اپ ڈیٹ کیا گیا"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"آپ کے منتظم کے ذریعے حذف کیا گیا"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ٹھیک ہے"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"بیٹری سیور گہری تھیم کو آن کرتی ہے اور پس منظر کی سرگرمی، کچھ بصری اثرات اور \"Hey Google\" جیسی خصوصیات کو محدود یا آف کرتی ہے\n\n"<annotation id="url">"مزید جانیں"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"بیٹری سیور گہری تھیم کو آن کرتی ہے اور پس منظر کی سرگرمی، کچھ بصری اثرات اور \"Hey Google\" جیسی خصوصیات کو محدود یا آف کرتی ہے۔"</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (5693741424234005958) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"ڈیٹا کے استعمال کو کم کرنے میں مدد کیلئے، ڈیٹا سیور پس منظر میں کچھ ایپس کو ڈیٹا بھیجنے یا موصول کرنے سے روکتی ہے۔ آپ جو ایپ فی الحال استعمال کر رہے ہیں وہ ڈیٹا تک رسائی کر سکتی ہے مگر ہو سکتا ہے ایسا اکثر نہ ہو۔ اس کا مطلب مثال کے طور پر یہ ہو سکتا ہے کہ تصاویر تھپتھپانے تک ظاہر نہ ہوں۔"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ڈیٹا سیور آن کریں؟"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"آن کریں"</string>
@@ -2073,12 +2088,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"اس اطلاع کو خاموش پر ڈیموٹ کیا گيا۔ تاثرات فراہم کرنے کے ليے تھپتھپائیں۔"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"اس اطلاع کو اعلی درجہ دیا گیا۔ تاثرات فراہم کرنے کے ليے تھپتھپائیں۔"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"اس اطلاع کو کم درجہ دیا گیا۔ تاثرات فراہم کرنے کے ليے تھپتھپائیں۔"</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"بہتر کردہ اطلاعات آزمائیں"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"تجویز کردہ کارروائیاں، جوابات اور مزید بہت کچھ حاصل کرنا جاری رکھنے کے لیے بہتر کردہ اطلاعات آن کریں۔ Android اڈاپٹیو اطلاعات اب تعاون یافتہ نہیں ہیں۔"</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"آن کریں"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ابھی نہیں"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"مزید جانیں"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"بہتر کردہ اطلاعات رابطوں کے نام اور پیغامات جیسی ذاتی معلومات سمیت تمام اطلاعی مواد پڑھ سکتی ہیں۔ یہ خصوصیت اطلاعات کو برخاست بھی کر سکتی ہے یا کالز کا جواب دینے جیسے اطلاعات میں نظر آنے والے بٹنوں سے کارروائیاں کر سکتی ہے۔\n\nیہ خصوصیت ترجیحی موڈ کو آن یا آف بھی کر سکتی ہے اور متعلقہ ترتیبات کو تبدیل کر سکتی ہے۔"</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"روٹین موڈ معلومات کی اطلاع"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"معمول چارج سے پہلے بیٹری ختم ہو سکتی ہے"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"بیٹری لائف کو بڑھانے کے لیے بیٹری سیور کو فعال کر دیا گیا ہے"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 012f31e..bac2b6f 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1708,7 +1708,7 @@
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Tezkor ishga tushirishni o‘chirib qo‘yish"</string>
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Tezkor ishga tushirishdan foydalanish"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Ranglarni akslantirish"</string>
- <string name="color_correction_feature_name" msgid="3655077237805422597">"Rangni tuzatish"</string>
+ <string name="color_correction_feature_name" msgid="3655077237805422597">"Ranglarni tuzatish"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Juda xira"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tovush tugmalari bosib turildi. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> yoqildi."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tovush tugmalari bosib turildi. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> faolsizlantirildi."</string>
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarx"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,8 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <!-- no translation found for mediasize_japanese_l (1326765321473431817) -->
+ <skip />
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Noma’lum bo‘yiga"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Noma’lum eniga"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Bekor qilindi"</string>
@@ -1852,8 +1865,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administrator tomonidan yangilangan"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administrator tomonidan o‘chirilgan"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Quvvat tejash funksiyasi Tungi mavzuni va cheklovlarni yoqadi va fondagi harakatlar, vizual effektlar va “Ok Google” kabi boshqa funksiyalarni faolsizlantiradi yoki cheklaydi.\n\n"<annotation id="url">"Batafsil"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Quvvat tejash funksiyasi Tungi mavzuni va cheklovlarni yoqadi va fondagi harakatlar, vizual effektlar va “Ok Google” kabi boshqa funksiyalarni faolsizlantiradi yoki cheklaydi."</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (5693741424234005958) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"Trafik tejash rejimida ayrim ilovalar uchun orqa fonda internetdan foydalanish imkoniyati cheklanadi. Siz ishlatayotgan ilova zaruratga qarab internet-trafik sarflashi mumkin, biroq cheklangan miqdorda. Masalan, rasmlar ustiga bosmaguningizcha ular yuklanmaydi."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Trafik tejash yoqilsinmi?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Yoqish"</string>
@@ -2073,12 +2088,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Bu bildirishnoma darajasi Tovushsiz darajaga tushirildi Fikr-mulohaza bildirish uchun bosing."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Bu bildirishnoma darajasi oshirildi. Fikr-mulohaza bildirish uchun bosing."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Bu bildirishnoma darajasi pasaytirildi. Fikr-mulohaza bildirish uchun bosing."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Yangicha bildirishnomalar"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Amallar, javoblar va boshqa takliflarni olishda davom etish uchun yaxshilangan bildirishnomalarni yoqing. Android moslashuvchan bildirishnomalari endi ishlamaydi."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Yoqish"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Hozir emas"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Yangicha bildirishnomalar"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Amallar va javoblar taklifi endi yangicha bildirishnomalar orqali chiqadi. Android moslashuvchan bildirishnomalari endi ishlamaydi."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Faolsizlantirish"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Batafsil"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Yangicha bildirishnomalar funksiyasi barcha bildirishnomalarni, jumladan, shaxsiy maʼlumotlarni (kontakt nomlari va xabarlar) oʻqiy oladi. Shuningdek, bu funksiya bildirishnomalarni yopishi yoki telefon chaqiruvlariga javob berish kabi bildirishnomalarda tugmalar bilan amallar bajarishi mumkin.\n\nBu funksiya Faqat muhim rejimini yoqishi va faolsizlantirishi yoki unga aloqador sozlamalarni oʻzgartirishi ham mumkin."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12 tizimida moslashuvchan bildirishnomalar oʻrniga yangicha bildirishnomalar chiqadi. Bu funksiya amallar va javoblarni taklif qiladi va bildirishnomalaringizni boshqaradi.\n\nYangicha bildirishnomalar barcha bildirishnomalar kontentini, jumladan kontakt nomlari va xabarlar kabi shaxsiy bildirishnomalarni ham oʻqiy oladi. Shuningdek, bu funksiya bildirishnomalarni yopishi yoki telefon chaqiruvlariga javob berishi va Bezovta qilinmasin rejimini boshqarishi mumkin."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Kun tartibi rejimi haqidagi bildirishnoma"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batareya quvvati odatdagidan ertaroq tugashi mumkin"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batareya quvvatini uzoqroq vaqtga yetkazish uchun quvvat tejash rejimi yoqildi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ccbcd0a..c65229c 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Giấy khổ rộng"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Khổ dọc không xác định"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Khổ ngang không xác định"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Đã hủy"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Do quản trị viên của bạn cập nhật"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Do quản trị viên của bạn xóa"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Tính năng Tiết kiệm pin sẽ bật Giao diện tối, đồng thời tắt hoặc hạn chế hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng như lệnh “Ok Google”\n\n"<annotation id="url">"Tìm hiểu thêm"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Tính năng Tiết kiệm pin sẽ bật Giao diện tối, đồng thời tắt hoặc hạn chế hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng như lệnh “Ok Google”."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Tính năng Tiết kiệm pin sẽ bật Giao diện tối, đồng thời hạn chế hoặc tắt hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng nhất định.\n\n"<annotation id="url">"Tìm hiểu thêm"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Tính năng Tiết kiệm pin sẽ bật Giao diện tối, đồng thời hạn chế hoặc tắt hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng nhất định."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Để giúp giảm mức sử dụng dữ liệu, Trình tiết kiệm dữ liệu sẽ chặn một số ứng dụng gửi hoặc nhận dữ liệu trong nền. Ứng dụng mà bạn hiện sử dụng có thể dùng dữ liệu nhưng tần suất sẽ giảm. Ví dụ: hình ảnh sẽ không hiển thị cho đến khi bạn nhấn vào hình ảnh đó."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Bật Trình tiết kiệm dữ liệu?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Bật"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Hệ thống đã hạ mức ưu tiên của thông báo này xuống thành Im lặng. Hãy nhấn để chia sẻ ý kiến phản hồi."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Hệ thống đã nâng mức ưu tiên của thông báo này. Hãy nhấn để chia sẻ ý kiến phản hồi."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Hệ thống đã hạ mức ưu tiên của thông báo này. Hãy nhấn để chia sẻ ý kiến phản hồi."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Dùng thử thông báo nâng cao"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Để tiếp tục nhận các thao tác đề xuất, câu trả lời và nhiều nội dung khác, hãy bật thông báo nâng cao. Thông báo thích ứng trên Android không được hỗ trợ nữa."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Bật"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Để sau"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Tìm hiểu thêm"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Thông báo nâng cao có thể đọc mọi nội dung thông báo, bao gồm cả thông tin cá nhân như tên liên hệ và tin nhắn. Tính năng này cũng có thể đóng các thông báo hoặc thực hiện thao tác đối với các nút trong thông báo, chẳng hạn như trả lời cuộc gọi điện thoại.\n\nTính năng này cũng có thể bật hoặc tắt Chế độ ưu tiên và thay đổi các chế độ cài đặt liên quan."</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Thông báo cung cấp thông tin về chế độ sạc thông thường"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Pin có thể hết trước khi sạc bình thường"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Trình tiết kiệm pin được kích hoạt để kéo dài thời lượng pin"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index d7f3165..df13cc0 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,8 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <!-- no translation found for mediasize_japanese_l (1326765321473431817) -->
+ <skip />
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"未知(纵向)"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"未知(横向)"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"已取消"</string>
@@ -1852,8 +1865,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由您的管理员更新"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"已由您的管理员删除"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"确定"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"省电模式会开启深色主题,并限制或关闭后台活动、部分视觉效果和“Ok Google”等功能\n\n"<annotation id="url">"了解详情"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"省电模式会开启深色主题,并限制或关闭后台活动、部分视觉效果和“Ok Google”等功能。"</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (5693741424234005958) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"为了减少流量消耗,流量节省程序会阻止某些应用在后台收发数据。您当前使用的应用可以收发数据,但频率可能会降低。举例而言,这可能意味着图片只有在您点按之后才会显示。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"要开启流量节省程序吗?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"开启"</string>
@@ -2073,12 +2088,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"系统已将此通知的重要性降低为“静音”。点按即可提供反馈。"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"系统已提升此通知的重要性。点按即可提供反馈。"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"系统已降低此通知的重要性。点按即可提供反馈。"</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"试用增强型通知"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"如需继续接收建议的操作、回复等内容,请开启增强型通知功能。系统不再支持 Android 自动调节通知功能。"</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"开启"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"以后再说"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"了解详情"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"增强型通知功能可以读取所有通知内容,包括联系人姓名和消息等个人信息。该功能也能关闭通知或触发通知中的按钮,例如接听来电。\n\n此外,该功能还能开启或关闭“优先”模式,以及更改相关设置。"</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"日常安排模式信息通知"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"电池电量可能会在您平时的充电时间之前耗尽"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"已启用省电模式以延长电池续航时间"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 858c179..3addf92e 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"不明直向紙張"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"不明橫向紙張"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"已取消"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由您的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"已由您的管理員刪除"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"好"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"「省電模式」會開啟深色主題背景並限制或關閉背景活動、部分視覺效果,以及「Ok Google」啟動字詞等功能。\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"「省電模式」會開啟深色主題背景並限制或關閉背景活動、部分視覺效果,以及「Ok Google」啟動字詞等功能。"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"「省電模式」會開啟深色主題背景,並限制或關閉背景活動、部分視覺效果和特定功能。\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"「省電模式」會開啟深色主題背景,並限制或關閉背景活動、部分視覺效果和特定功能。"</string>
<string name="data_saver_description" msgid="4995164271550590517">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。您正在使用的應用程式可存取資料,但次數可能會減少。例如,圖片可能需要輕按才會顯示。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"要開啟「數據節省模式」嗎?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"開啟"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"此通知的重要性已降低為「靜音」。輕按即可提供意見。"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"此通知的重要性已提升。輕按即可提供意見。"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"此通知的重要性已降級。輕按即可提供意見。"</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"試用強化通知"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"如要繼續收到建議操作和回覆等內容,請開啟強化通知功能。系統已不再支援 Android 自動調整通知功能。"</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"開啟"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"暫時不要"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"瞭解詳情"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"強化通知功能可讀取所有通知內容 (包括聯絡人姓名和訊息等個人資料),以及關閉通知或針對通知中的按鈕採取行動,例如接聽來電。\n\n此功能亦可開啟或關閉「優先」模式及變更相關設定。"</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"「日常安排模式」資料通知"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"電量可能會在日常充電前耗盡"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"「省電模式」已啟用,以便延長電池壽命"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 8770db7..08071be 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"不明縱向紙張"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"不明橫向紙張"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"已取消"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由你的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"已由你的管理員刪除"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"確定"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"省電模式會開啟深色主題並限制或關閉背景活動、部分視覺效果,以及「Ok Google」啟動字詞等功能\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"省電模式會開啟深色主題並限制或關閉背景活動、部分視覺效果,以及「Ok Google」啟動字詞等功能。"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"省電模式會開啟深色主題,並限制或關閉背景活動、某些視覺效果和特定功能。\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"省電模式會開啟深色主題,並限制或關閉背景活動、某些視覺效果和特定功能。"</string>
<string name="data_saver_description" msgid="4995164271550590517">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。你目前使用的應用程式可以存取資料,但存取頻率可能不如平時高。舉例來說,圖片可能不會自動顯示,在你輕觸後才會顯示。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"要開啟數據節省模式嗎?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"開啟"</string>
@@ -2073,12 +2085,17 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"這則通知的重要性已降低為「靜音」。輕觸即可提供意見。"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"這則通知的重要性順序已調高。輕觸即可提供意見。"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"這則通知的重要性順序已調降。輕觸即可提供意見。"</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"試試看加強型通知"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"如要繼續收到建議的操作、回覆等內容,請開啟加強型通知功能。系統已不再支援 Android 自動調整通知功能。"</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"開啟"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"暫時不要"</string>
+ <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) -->
+ <skip />
+ <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) -->
+ <skip />
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"瞭解詳情"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"加強型通知功能可讀取所有通知內容,包括聯絡人名稱和訊息內文等個人資訊。這項功能也能關閉通知或操作通知中的按鈕,例如接聽來電。\n\n此外,這項功能還可以開啟或關閉「優先」模式及變更相關設定。"</string>
+ <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) -->
+ <skip />
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"日常安排模式資訊通知"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"電池電力可能會在你平常的充電時間前耗盡"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"已啟用省電模式以延長電池續航力"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 4a912d4..07a597b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1773,6 +1773,17 @@
<string name="mediasize_na_monarch" msgid="4396943937986136896">"I-Monarch"</string>
<string name="mediasize_na_quarto" msgid="2119101847712239885">"I-Quarto"</string>
<string name="mediasize_na_foolscap" msgid="5011612828564394648">"I-Foolscap"</string>
+ <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string>
+ <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string>
+ <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string>
+ <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string>
+ <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string>
+ <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string>
+ <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string>
+ <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string>
+ <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string>
+ <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string>
+ <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super-B"</string>
<string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"I-ROC 8K"</string>
<string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"I-ROC 16K"</string>
<string name="mediasize_chinese_prc_1" msgid="946949835711037253">"I-PRC 1"</string>
@@ -1809,6 +1820,7 @@
<string name="mediasize_japanese_kahu" msgid="7290232592648122042">"I-Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"I-Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"I-You4"</string>
+ <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Ukuma ngobude obungaziwa"</string>
<string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Ukwakheka kwezwe okungaziwa"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Kukhanseliwe"</string>
@@ -1852,8 +1864,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Kubuyekezwe umlawuli wakho"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Kususwe umlawuli wakho"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"KULUNGILE"</string>
- <string name="battery_saver_description_with_learn_more" msgid="7963058670863485450">"Isilondolozi Sebhethri sivula Itimu Emnyama futhi sikhawulele noma sivale umsebenzi wendawo engemuva, izakhi ezithile ezibonakalayo, nezakhi ezinjenge-\"Ok Google\"\n\n"<annotation id="url">"Funda kabanzi"</annotation></string>
- <string name="battery_saver_description" msgid="7695751399533397741">"Isilondolozi Sebhethri sivula Itimu Emnyama futhi sikhawulele noma sivale umsebenzi wendawo engemuva, izakhi ezithile ezibonakalayo, nezakhi ezinjenge-\"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Isilondolozi Sebhethri sivula Itimu emnyama futhi silinganise noma sivale umsebenzi ongemuva, imiphumela ethile yokubuka, nezakhi ezithile.\n\n"<annotation id="url">"Funda kabanzi"</annotation></string>
+ <string name="battery_saver_description" msgid="5693741424234005958">"Isilondolozi Sebhethri sivula itimu emnyama futhi silinganise noma sivale umsebenzi ongemuva, imiphumela ethile yokubuka, nezakhi ezithile."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Ukusiza ukwehlisa ukusetshenziswa kwedatha, iseva yedatha igwema ezinye izinhlelo zokusebenza ukuthi zithumele noma zamukele idatha ngasemuva. Uhlelo lokusebenza olisebenzisa okwamanje lingafinyelela idatha, kodwa lingenza kanjalo kancane. Lokhu kungachaza, isibonelo, ukuthi izithombe azibonisi uze uzithephe."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vula iseva yedatha?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Vula"</string>
@@ -2073,12 +2085,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Lesi saziso sehliselwe esikhundleni Sokuthula. Thepha ukuze unikeze impendulo."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Lesi saziso sibekwe ezingeni eliphakeme. Thepha ukuze unikeze impendulo."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Lesi saziso sibekwe ezingeni eliphansi. Thepha ukuze unikeze impendulo."</string>
- <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Zama izaziso ezigqanyisiwe"</string>
- <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Ukuze uqhubeke nokuthola izenzo eziphakanyisiwe, izimpendulo nokuningi, vula izaziso ezigqanyisiwe. Izaziso ze-Androin Ezivumelana Nezimo azisasekelwe."</string>
- <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Vula"</string>
- <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Hhayi manje"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Izaziso ezigqanyisiwe"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Izenzo nezimpendulo eziphakanyisiwe manje sezihlinzekwa ngezaziso ezithuthukisiwe. Izaziso ze-Androin Ezivumelana Nezimo azisasekelwe."</string>
+ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"KULUNGILE"</string>
+ <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Vala"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Funda kabanzi"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Izaziso ezigqanyisiwe zingafunda konke okuqukethwe yizaziso zakho, kuhlanganise nolwazi lomuntu siqu njengamagama oxhumana nabo nemilayezo. Lesi sakhi singacashisa izaziso noma sithathe izinyathelo ezinkinobheni ezisezazisweni, njengokuphendula amakholi wefoni.\n\nLesi sici singavula noma sivale nemodi Yokubalulekile futhi sishintshe amasethingi ahambisanayo."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Izaziso ezithuthukisiwe zithathe isikhundla sezaziso eziguqukayo ze-Android ku-Android 12. Lesi sici sikhombisa izenzo eziphakanyisiwe nezimpendulo, futhi sihlela izaziso zakho.\n\nIzaziso ezithuthukisiwe zingafinyelela kokuqukethwe kwesaziso, kuhlanganise nemininingwane yomuntu efana namagama woxhumana nabo nemilayezo. Lesi sakhi singacashisa noma siphendule izaziso, njengokuphendula amakholi efoni nokulawula ukuthi Ungaphazamisi."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Isaziso solwazi lwe-Routine Mode"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Ibhethri lingaphela ngaphambi kokushaja okuvamile"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Isilondolozi sebhethri siyasebenza ngaphandle kwempilo yebhethri"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 529aa66..fbc9678 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -657,6 +657,12 @@
<!-- Indicate the display area rect for foldable devices in folded state. -->
<string name="config_foldedArea"></string>
+ <!-- Indicates that the device supports having more than one internal display on at the same
+ time. Only applicable to devices with more than one internal display. If this option is
+ set to false, DisplayManager will make additional effort to ensure no more than 1 internal
+ display is powered on at the same time. -->
+ <bool name="config_supportsConcurrentInternalDisplays">true</bool>
+
<!-- Desk dock behavior -->
<!-- The number of degrees to rotate the display when the device is in a desk dock.
@@ -4854,17 +4860,30 @@
<!-- Whether app hibernation deletes OAT artifact files as part of global hibernation. -->
<bool name="config_hibernationDeletesOatArtifactsEnabled">true</bool>
- <!-- On-device intelligent processor for system UI features. -->
+ <!-- Package name of the on-device intelligent processor for system UI
+ features. Examples include the search functionality or the app
+ predictor. -->
<string name="config_systemUiIntelligence" translatable="false"></string>
- <!-- On-device intelligent processor for ambient audio. -->
+ <!-- Package name of the on-device intelligent processor for ambient audio.
+ Ambient audio is the sound surrounding the device captured by the DSP
+ or the microphone. In other words, the device is continuously
+ processing audio data in background. -->
<string name="config_systemAmbientAudioIntelligence" translatable="false"></string>
- <!-- On-device intelligent processor for audio. -->
+ <!-- Package name of the on-device intelligent processor for audio. The
+ difference of 'ambient audio' and 'audio' is that in 'audio', the
+ user intentionally and consciously aware that the device is recording
+ or using the microphone.
+ -->
<string name="config_systemAudioIntelligence" translatable="false"></string>
- <!-- On-device intelligent processor for notification. -->
+ <!-- Package name of the on-device intelligent processor for notification.
+ -->
<string name="config_systemNotificationIntelligence" translatable="false"></string>
- <!-- On-device intelligent processor for text. -->
+ <!-- Package name of the on-device intelligent processor for text. Examples
+ include providing autofill functionality based on incoming text
+ messages. -->
<string name="config_systemTextIntelligence" translatable="false"></string>
- <!-- On-device intelligent processor for visual features. -->
+ <!-- Package name of the on-device intelligent processor for visual
+ features. Examples include the autorotate feature. -->
<string name="config_systemVisualIntelligence" translatable="false"></string>
<!-- On-device package for providing companion device associations. -->
<string name="config_systemCompanionDeviceProvider" translatable="false"></string>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 43c0ec9..fc3ed63 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -367,6 +367,9 @@
<!-- The spacing between messages in Notification.MessagingStyle -->
<dimen name="notification_messaging_spacing">6dp</dimen>
+ <!-- The spacing between messages in Notification.MessagingStyle -->
+ <dimen name="notification_messaging_spacing_conversation_group">24dp</dimen>
+
<!-- The rounding for messaging images -->
<dimen name="messaging_image_rounding">4dp</dimen>
@@ -760,7 +763,7 @@
<!-- The maximum size of the grayscale icon -->
<dimen name="notification_grayscale_icon_max_size">256dp</dimen>
- <dimen name="messaging_avatar_size">36dp</dimen>
+ <dimen name="messaging_avatar_size">48dp</dimen>
<dimen name="conversation_avatar_size">48dp</dimen>
<!-- start margin of the icon circle in the conversation's skin of the header -->
<dimen name="conversation_icon_circle_start">28dp</dimen>
@@ -779,17 +782,17 @@
<!-- size of the face pile icons -->
<dimen name="conversation_face_pile_avatar_size">32dp</dimen>
<!-- size of the face pile icons when the group is expanded -->
- <dimen name="conversation_face_pile_avatar_size_group_expanded">25dp</dimen>
+ <dimen name="conversation_face_pile_avatar_size_group_expanded">@dimen/conversation_face_pile_avatar_size</dimen>
<!-- Side margins of the conversation badge in relation to the conversation icon when the group is expanded-->
- <dimen name="conversation_badge_side_margin_group_expanded">22dp</dimen>
+ <dimen name="conversation_badge_side_margin_group_expanded">@dimen/conversation_badge_side_margin</dimen>
<!-- Side margins of the conversation badge in relation to the conversation icon when the group is expanded-->
- <dimen name="conversation_badge_side_margin_group_expanded_face_pile">18dp</dimen>
+ <dimen name="conversation_badge_side_margin_group_expanded_face_pile">@dimen/conversation_badge_side_margin</dimen>
<!-- The width of the protection of the face pile layout-->
<dimen name="conversation_face_pile_protection_width">2dp</dimen>
<!-- The width of the protection of the face pile layout when expanded-->
- <dimen name="conversation_face_pile_protection_width_expanded">1dp</dimen>
+ <dimen name="conversation_face_pile_protection_width_expanded">@dimen/conversation_face_pile_protection_width</dimen>
<!-- The padding of the expanded message container-->
- <dimen name="expanded_group_conversation_message_padding">17dp</dimen>
+ <dimen name="expanded_group_conversation_message_padding">32dp</dimen>
<!-- The stroke width of the ring used to visually mark a conversation as important -->
<dimen name="importance_ring_stroke_width">2dp</dimen>
<!-- The maximum stroke width used for the animation shown when a conversation is marked as important -->
@@ -801,7 +804,7 @@
<dimen name="conversation_icon_container_top_padding">20dp</dimen>
<!-- The top padding of the conversation icon container when the avatar is small-->
- <dimen name="conversation_icon_container_top_padding_small_avatar">9dp</dimen>
+ <dimen name="conversation_icon_container_top_padding_small_avatar">8dp</dimen>
<!-- The padding of the conversation header when expanded. This is calculated from the expand button size + notification_content_margin_end -->
<dimen name="conversation_header_expanded_padding_end">38dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index cc347f9..fd33ccd 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5539,19 +5539,19 @@
<!-- Content description of the demoted feedback icon in the notification. [CHAR LIMIT=NONE] -->
<string name="notification_feedback_indicator_demoted">This notification was ranked lower. Tap to provide feedback.</string>
- <!-- Notification Intelligence -->
- <!-- Title of notification indicating notification intelligence settings have changed when upgrading to S [CHAR LIMIT=30] -->
- <string name="nas_upgrade_notification_title">Try enhanced notifications</string>
+ <!-- Enhanced Notifications -->
+ <!-- Title of notification indicating adaptive notifications setting need migration when upgrading to S [CHAR LIMIT=30] -->
+ <string name="nas_upgrade_notification_title">Enhanced notifications</string>
<!-- Content of notification indicating users need to update the settings [CHAR LIMIT=NONE] -->
- <string name="nas_upgrade_notification_content">To keep getting suggested actions, replies, and more, turn on enhanced notifications. Android Adaptive Notifications are no longer supported.</string>
- <!-- Label of notification action button to turn on the notification intelligence [CHAR LIMIT=20] -->
- <string name="nas_upgrade_notification_enable_action">Turn on</string>
- <!-- Label of notification action button to turn off the notification intelligence [CHAR LIMIT=20] -->
- <string name="nas_upgrade_notification_disable_action">Not now</string>
- <!-- Label of notification action button to learn more about the notification intelligence settings [CHAR LIMIT=20] -->
+ <string name="nas_upgrade_notification_content">Suggested actions and replies are now provided by enhanced notifications. Android Adaptive Notifications are no longer supported.</string>
+ <!-- Label of notification action button to turn on the enhanced notifications [CHAR LIMIT=20] -->
+ <string name="nas_upgrade_notification_enable_action">OK</string>
+ <!-- Label of notification action button to turn off the enhanced notifications [CHAR LIMIT=20] -->
+ <string name="nas_upgrade_notification_disable_action">Turn off</string>
+ <!-- Label of notification action button to learn more about the enhanced notifications [CHAR LIMIT=20] -->
<string name="nas_upgrade_notification_learn_more_action">Learn more</string>
- <!-- Content of notification learn more dialog about the notification intelligence settings [CHAR LIMIT=NONE] -->
- <string name="nas_upgrade_notification_learn_more_content">Enhanced notifications can read all notification content, including personal information like contact names and messages. This feature can also dismiss notifications or take actions on buttons in notifications, such as answering phone calls.\n\nThis feature can also turn Priority mode on or off and change related settings.</string>
+ <!-- Content of notification learn more dialog about the enhanced notifications [CHAR LIMIT=NONE] -->
+ <string name="nas_upgrade_notification_learn_more_content">Enhanced notifications replaced Android Adaptive Notifications in Android 12. This feature shows suggested actions and replies, and organizes your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls and controlling Do Not Disturb.</string>
<!-- Dynamic mode battery saver strings -->
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 439ae48..ad0d0e0 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -302,10 +302,6 @@
<style name="TextAppearance.DeviceDefault.Notification.Time" parent="TextAppearance.Material.Notification.Time">
<item name="fontFamily">@string/config_bodyFontFamily</item>
</style>
- <style name="TextAppearance.DeviceDefault.Notification.Conversation.AppName"
- parent="TextAppearance.Material.Notification.Conversation.AppName">
- <item name="fontFamily">@string/config_headlineFontFamilyMedium</item>
- </style>
<style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Material.Widget">
<item name="fontFamily">@string/config_bodyFontFamily</item>
</style>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 3c4a5d4..eec6ae3 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -497,10 +497,6 @@
<!-- unused; keep identical to parent -->
<style name="TextAppearance.Material.Notification.Emphasis"/>
- <style name="TextAppearance.Material.Notification.Conversation.AppName" parent="TextAppearance.Material.Notification.Title">
- <item name="android:textSize">16sp</item>
- </style>
-
<style name="TextAppearance.Material.ListItem" parent="TextAppearance.Material.Subhead" />
<style name="TextAppearance.Material.ListItemSecondary" parent="TextAppearance.Material.Body1" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 78a794a..d62f2bc 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3083,6 +3083,7 @@
<java-symbol type="string" name="negative_duration" />
<java-symbol type="dimen" name="notification_messaging_spacing" />
+ <java-symbol type="dimen" name="notification_messaging_spacing_conversation_group" />
<java-symbol type="dimen" name="notification_text_margin_top" />
<java-symbol type="dimen" name="notification_inbox_item_top_padding" />
@@ -3800,6 +3801,7 @@
<!-- For Foldables -->
<java-symbol type="array" name="config_foldedDeviceStates" />
<java-symbol type="string" name="config_foldedArea" />
+ <java-symbol type="bool" name="config_supportsConcurrentInternalDisplays" />
<java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" />
<java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" />
@@ -4089,7 +4091,6 @@
<java-symbol type="dimen" name="button_inset_horizontal_material" />
<java-symbol type="layout" name="conversation_face_pile_layout" />
<java-symbol type="string" name="unread_convo_overflow" />
- <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Conversation.AppName" />
<java-symbol type="drawable" name="conversation_badge_background" />
<java-symbol type="drawable" name="conversation_badge_ring" />
<java-symbol type="color" name="conversation_important_highlight" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index d5733e3..2650d9f 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -40,7 +40,7 @@
<shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
<!-- Argentina: 5 digits, known short codes listed -->
- <shortcode country="ar" pattern="\\d{5}" free="11711|28291" />
+ <shortcode country="ar" pattern="\\d{5}" free="11711|28291|44077" />
<!-- Armenia: 3-4 digits, emergency numbers 10[123] -->
<shortcode country="am" pattern="\\d{3,4}" premium="11[2456]1|3024" free="10[123]" />
@@ -76,14 +76,14 @@
<shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111|30118" free="98765|30075|30047" />
<!-- Chile: 4-5 digits (not confirmed), known premium codes listed -->
- <shortcode country="cl" pattern="\\d{4,5}" free="9963|9240" />
+ <shortcode country="cl" pattern="\\d{4,5}" free="9963|9240|1038" />
<!-- China: premium shortcodes start with "1066", free shortcodes start with "1065":
http://clients.txtnation.com/entries/197192-china-premium-sms-short-code-requirements -->
<shortcode country="cn" premium="1066.*" free="1065.*" />
<!-- Colombia: 1-6 digits (not confirmed) -->
- <shortcode country="co" pattern="\\d{1,6}" free="890350|908160|892255|898002|898880|899960" />
+ <shortcode country="co" pattern="\\d{1,6}" free="890350|908160|892255|898002|898880|899960|899948|87739" />
<!-- Cyprus: 4-6 digits (not confirmed), known premium codes listed, plus EU -->
<shortcode country="cy" pattern="\\d{4,6}" premium="7510" free="116\\d{3}" />
@@ -156,7 +156,7 @@
<shortcode country="jp" pattern="\\d{1,5}" free="8083" />
<!-- Kenya: 5 digits, known premium codes listed -->
- <shortcode country="ke" pattern="\\d{5}" free="21725" />
+ <shortcode country="ke" pattern="\\d{5}" free="21725|21562|40520" />
<!-- Kyrgyzstan: 4 digits, known premium codes listed -->
<shortcode country="kg" pattern="\\d{4}" premium="415[2367]|444[69]" />
@@ -187,13 +187,13 @@
<shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963" />
<!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf -->
- <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288" />
+ <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668" />
<!-- The Netherlands, 4 digits, known premium codes listed, plus EU -->
<shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" />
<!-- Nigeria -->
- <shortcode country="ng" pattern="\\d{1,5}" free="2441" />
+ <shortcode country="ng" pattern="\\d{1,5}" free="2441|55019" />
<!-- Norway: 4-5 digits (not confirmed), known premium codes listed -->
<shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" free="2171" />
@@ -202,7 +202,7 @@
<shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="1737|176|2141|3067|3068|3110|4006|4053|4061|4062|4202|4300|4334|4412|4575|5626|8006|8681" />
<!-- Peru: 4-5 digits (not confirmed), known premium codes listed -->
- <shortcode country="pe" pattern="\\d{4,5}" free="9963" />
+ <shortcode country="pe" pattern="\\d{4,5}" free="9963|40777" />
<!-- Philippines -->
<shortcode country="ph" pattern="\\d{1,5}" free="2147|5495|5496" />
@@ -224,7 +224,7 @@
<shortcode country="re" pattern="\\d{1,5}" free="38600,36300,36303,959" />
<!-- Romania: 4 digits, plus EU: http://www.simplus.ro/en/resources/glossary-of-terms/ -->
- <shortcode country="ro" pattern="\\d{4}" premium="12(?:63|66|88)|13(?:14|80)" free="116\\d{3}|3654|8360" />
+ <shortcode country="ro" pattern="\\d{4}" premium="12(?:63|66|88)|13(?:14|80)" free="116\\d{3}|3654|8360|3838" />
<!-- Russia: 4 digits, known premium codes listed: http://smscoin.net/info/pricing-russia/ -->
<shortcode country="ru" pattern="\\d{4}" premium="1(?:1[56]1|899)|2(?:09[57]|322|47[46]|880|990)|3[589]33|4161|44(?:4[3-9]|81)|77(?:33|81)|8424" free="6954|8501" standard="2037|2044"/>
@@ -252,7 +252,7 @@
<shortcode country="tj" pattern="\\d{4}" premium="11[3-7]1|4161|4333|444[689]" />
<!-- Turkey -->
- <shortcode country="tr" pattern="\\d{1,5}" free="7529|5528|6493" />
+ <shortcode country="tr" pattern="\\d{1,5}" free="7529|5528|6493|3193" />
<!-- Ukraine: 4 digits, known premium codes listed -->
<shortcode country="ua" pattern="\\d{4}" premium="444[3-9]|70[579]4|7540" />
@@ -268,6 +268,6 @@
<shortcode country="yt" pattern="\\d{1,5}" free="38600,36300,36303,959" />
<!-- South Africa -->
- <shortcode country="za" pattern="\d{1,5}" free="44136" />
+ <shortcode country="za" pattern="\d{1,5}" free="44136|30791|36056" />
</shortcodes>
diff --git a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetrics.java b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetrics.java
index 0f3bb1d..81ec3f3 100644
--- a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetrics.java
+++ b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetrics.java
@@ -58,11 +58,8 @@
for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT;
component++) {
- totalPowerPerComponentMah[component] += uidBatteryConsumer.getConsumedPower(
- component);
- }
-
- for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT; component++) {
+ totalPowerPerComponentMah[component] +=
+ uidBatteryConsumer.getConsumedPower(component);
totalDurationPerComponentMs[component] +=
uidBatteryConsumer.getUsageDurationMillis(component);
}
@@ -76,18 +73,15 @@
addMetric(getPowerMetricName(component), MetricKind.POWER,
selectedBatteryConsumer.getConsumedPower(component),
totalPowerPerComponentMah[component]);
- }
-
- for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT; component++) {
- addMetric(getTimeMetricName(component), MetricKind.DURATION,
+ addMetric(getDurationMetricName(component), MetricKind.DURATION,
selectedBatteryConsumer.getUsageDurationMillis(component),
totalDurationPerComponentMs[component]);
}
}
- static String getTimeMetricName(int componentId) {
- return "TIME_" + DebugUtils.constantToString(BatteryConsumer.class,
- "TIME_COMPONENT_", componentId);
+ static String getDurationMetricName(int componentId) {
+ return "DURATION_" + DebugUtils.constantToString(BatteryConsumer.class,
+ "POWER_COMPONENT_", componentId);
}
static String getPowerMetricName(int componentId) {
diff --git a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetricsCollector.java b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetricsCollector.java
index 5b5da60..6fc10dd 100644
--- a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetricsCollector.java
+++ b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetricsCollector.java
@@ -306,8 +306,8 @@
return null;
}
- public PowerMetrics.Metric getTimeMetric(@BatteryConsumer.TimeComponent int component) {
- final String name = PowerMetrics.getTimeMetricName(component);
+ public PowerMetrics.Metric getTimeMetric(@BatteryConsumer.PowerComponent int component) {
+ final String name = PowerMetrics.getDurationMetricName(component);
for (PowerMetrics.Metric metric : mPowerMetricsDelta) {
if (metric.metricName.equals(name)) {
return metric;
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml b/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
index 52a77a7..1b1f64a 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
@@ -27,6 +27,7 @@
android:label="Battery Stats Viewer">
<activity android:name=".BatteryConsumerPickerActivity"
android:label="Battery Stats"
+ android:icon="@mipmap/ic_launcher"
android:launchMode="singleTop"
android:exported="true">
<intent-filter>
@@ -36,7 +37,6 @@
</activity>
<activity android:name=".BatteryStatsViewerActivity"
- android:icon="@mipmap/ic_launcher"
android:label="Battery Stats"
android:parentActivityName=".BatteryConsumerPickerActivity"/>
</application>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
index f7d7098..a15a8d8 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
@@ -68,7 +68,7 @@
double[] totalPowerByComponentMah = new double[BatteryConsumer.POWER_COMPONENT_COUNT];
double[] totalModeledPowerByComponentMah =
new double[BatteryConsumer.POWER_COMPONENT_COUNT];
- long[] totalDurationByComponentMs = new long[BatteryConsumer.TIME_COMPONENT_COUNT];
+ long[] totalDurationByComponentMs = new long[BatteryConsumer.POWER_COMPONENT_COUNT];
final int customComponentCount =
requestedBatteryConsumer.getCustomPowerComponentCount();
double[] totalCustomPowerByComponentMah = new double[customComponentCount];
@@ -108,7 +108,7 @@
mBatteryConsumerInfo.isSystemBatteryConsumer);
}
- for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT; component++) {
+ for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
final String metricTitle = getTimeMetricTitle(component);
addEntry(metricTitle, EntryType.DURATION,
requestedBatteryConsumer.getUsageDurationMillis(component),
@@ -141,7 +141,7 @@
static String getTimeMetricTitle(int componentId) {
final String componentName = DebugUtils.constantToString(BatteryConsumer.class,
- "TIME_COMPONENT_", componentId);
+ "POWER_COMPONENT_", componentId);
return componentName.charAt(0) + componentName.substring(1).toLowerCase().replace('_', ' ')
+ " time";
}
@@ -159,7 +159,7 @@
private void computeTotalDuration(BatteryUsageStats batteryUsageStats,
long[] durationByComponentMs) {
for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
- for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT;
+ for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT;
component++) {
durationByComponentMs[component] += consumer.getUsageDurationMillis(component);
}
diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
index b2b9ab3..c9a18da 100644
--- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
+++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
@@ -30,6 +30,7 @@
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -284,33 +285,42 @@
PasswordMetrics none = new PasswordMetrics(CREDENTIAL_TYPE_NONE);
PasswordMetrics pattern = new PasswordMetrics(CREDENTIAL_TYPE_PATTERN);
PasswordMetrics password = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
+ PasswordMetrics pin = new PasswordMetrics(CREDENTIAL_TYPE_PIN);
// To pass minimal length check.
password.length = 4;
+ pin.length = 4;
// No errors expected, credential is of stronger or equal type.
assertValidationErrors(
- validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, false, none));
+ validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, none));
assertValidationErrors(
- validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, false, pattern));
+ validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, pattern));
assertValidationErrors(
- validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, false, password));
+ validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, password));
assertValidationErrors(
- validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, false, pattern));
+ validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, pin));
assertValidationErrors(
- validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, false, password));
+ validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, pattern));
assertValidationErrors(
- validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, false, password));
+ validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, password));
+ assertValidationErrors(
+ validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, password));
+ assertValidationErrors(
+ validatePasswordMetrics(pin, PASSWORD_COMPLEXITY_NONE, pin));
// Now actual credential type is weaker than required:
assertValidationErrors(
- validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, false, none),
+ validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, none),
PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0);
assertValidationErrors(
- validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, false, none),
+ validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, none),
PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0);
assertValidationErrors(
- validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, false, pattern),
+ validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, pattern),
+ PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0);
+ assertValidationErrors(
+ validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, pin),
PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0);
}
diff --git a/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java b/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
index 36da927..3e2c4e9 100644
--- a/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
+++ b/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
@@ -234,6 +234,7 @@
.setIsImportantConversation(true)
.setStatuses(statusList).setNotificationKey("key")
.setNotificationContent("content")
+ .setNotificationSender("sender")
.setNotificationDataUri(Uri.parse("data"))
.setMessagesCount(2)
.setIntent(new Intent())
@@ -256,6 +257,7 @@
assertThat(readTile.getStatuses()).isEqualTo(tile.getStatuses());
assertThat(readTile.getNotificationKey()).isEqualTo(tile.getNotificationKey());
assertThat(readTile.getNotificationContent()).isEqualTo(tile.getNotificationContent());
+ assertThat(readTile.getNotificationSender()).isEqualTo(tile.getNotificationSender());
assertThat(readTile.getNotificationDataUri()).isEqualTo(tile.getNotificationDataUri());
assertThat(readTile.getMessagesCount()).isEqualTo(tile.getMessagesCount());
assertThat(readTile.getIntent().toString()).isEqualTo(tile.getIntent().toString());
@@ -282,6 +284,16 @@
}
@Test
+ public void testNotificationSender() {
+ PeopleSpaceTile tile = new PeopleSpaceTile
+ .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+ .setNotificationSender("test")
+ .build();
+
+ assertThat(tile.getNotificationSender()).isEqualTo("test");
+ }
+
+ @Test
public void testNotificationDataUri() {
PeopleSpaceTile tile =
new PeopleSpaceTile.Builder(new ShortcutInfo.Builder(mContext, "123").build(),
diff --git a/core/tests/coretests/src/android/os/VibratorInfoTest.java b/core/tests/coretests/src/android/os/VibratorInfoTest.java
index 9880f8c..8c7d10c 100644
--- a/core/tests/coretests/src/android/os/VibratorInfoTest.java
+++ b/core/tests/coretests/src/android/os/VibratorInfoTest.java
@@ -108,6 +108,8 @@
.build();
assertEquals(20, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK));
assertEquals(0, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_TICK));
+ assertEquals(0, new VibratorInfo.Builder(TEST_VIBRATOR_ID).build()
+ .getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_TICK));
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
index c63ec45..236c3da 100644
--- a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
@@ -65,7 +65,7 @@
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(
SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(90 * MINUTE_IN_MS);
// 100,000,00 uC / 1000 (micro-/milli-) / 360 (seconds/hour) = 27.777778 mAh
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
@@ -91,7 +91,7 @@
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(
SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(90 * MINUTE_IN_MS);
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isWithin(PRECISION).of(15.0);
diff --git a/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java
index ed4638c..c694d67 100644
--- a/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java
@@ -52,7 +52,7 @@
mStatsRule.apply(calculator);
UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO))
.isEqualTo(1000);
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO))
.isWithin(PRECISION).of(0.1);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
index e0739be..41fe372 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
@@ -171,7 +171,7 @@
final boolean includePowerModels = (query.getFlags()
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
- customPowerComponentNames, 0, includePowerModels);
+ customPowerComponentNames, includePowerModels);
SparseArray<? extends BatteryStats.Uid> uidStats = mBatteryStats.getUidStats();
for (int i = 0; i < uidStats.size(); i++) {
builder.getOrCreateUidBatteryConsumerBuilder(uidStats.valueAt(i));
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
index b253599..55302bc 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
@@ -67,7 +67,7 @@
final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(2000);
final BatteryUsageStats.Builder builder =
- new BatteryUsageStats.Builder(new String[]{"FOO"}, 1)
+ new BatteryUsageStats.Builder(new String[]{"FOO"})
.setDischargePercentage(20)
.setDischargedPowerRange(1000, 2000)
.setStatsStartTimestamp(1000);
@@ -83,11 +83,9 @@
.setConsumedPowerForCustomComponent(
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 500)
.setUsageDurationMillis(
- BatteryConsumer.TIME_COMPONENT_CPU, 600)
- .setUsageDurationMillis(
- BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND, 700)
+ BatteryConsumer.POWER_COMPONENT_CPU, 600)
.setUsageDurationForCustomComponentMillis(
- BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 800);
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 800);
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_CAMERA)
.setConsumedPower(
@@ -95,9 +93,9 @@
.setConsumedPowerForCustomComponent(
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200)
.setUsageDurationMillis(
- BatteryConsumer.TIME_COMPONENT_CPU, 10300)
+ BatteryConsumer.POWER_COMPONENT_CPU, 10300)
.setUsageDurationForCustomComponentMillis(
- BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 10400)
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10400)
.setPowerConsumedByApps(20000);
return builder.build();
@@ -129,11 +127,9 @@
assertThat(uidBatteryConsumer.getConsumedPowerForCustomComponent(
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(500);
assertThat(uidBatteryConsumer.getUsageDurationMillis(
- BatteryConsumer.TIME_COMPONENT_CPU)).isEqualTo(600);
- assertThat(uidBatteryConsumer.getUsageDurationMillis(
- BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND)).isEqualTo(700);
+ BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(600);
assertThat(uidBatteryConsumer.getUsageDurationForCustomComponentMillis(
- BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID)).isEqualTo(800);
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(800);
assertThat(uidBatteryConsumer.getConsumedPower()).isEqualTo(1200);
assertThat(uidBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1);
assertThat(uidBatteryConsumer.getCustomPowerComponentName(
@@ -152,9 +148,9 @@
assertThat(systemBatteryConsumer.getConsumedPowerForCustomComponent(
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(10200);
assertThat(systemBatteryConsumer.getUsageDurationMillis(
- BatteryConsumer.TIME_COMPONENT_CPU)).isEqualTo(10300);
+ BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(10300);
assertThat(systemBatteryConsumer.getUsageDurationForCustomComponentMillis(
- BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID)).isEqualTo(10400);
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(10400);
assertThat(systemBatteryConsumer.getConsumedPower()).isEqualTo(20300);
assertThat(systemBatteryConsumer.getPowerConsumedByApps()).isEqualTo(20000);
assertThat(systemBatteryConsumer.getUsageDurationMillis())
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index 7890168..8c5e0fc 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -938,17 +938,9 @@
}
@Test
- public void testLatencyCollectionDisabledByDefault() {
+ public void testLatencyCollectionEnabledByDefault() {
TestBinderCallsStats bcs = new TestBinderCallsStats();
- assertEquals(false, bcs.getCollectLatencyData());
-
- Binder binder = new Binder();
- CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
- bcs.time += 10;
- bcs.elapsedTime += 20;
- bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
-
- assertEquals(0, bcs.getLatencyObserver().getLatencyHistograms().size());
+ assertEquals(true, bcs.getCollectLatencyData());
}
private static class TestHandler extends Handler {
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index 71cdb5f..8723195 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -147,7 +147,7 @@
.isEqualTo(powerModel);
long usageDurationMillis = batteryConsumer.getUsageDurationMillis(
- BatteryConsumer.TIME_COMPONENT_BLUETOOTH);
+ BatteryConsumer.POWER_COMPONENT_BLUETOOTH);
assertThat(usageDurationMillis).isEqualTo(durationMs);
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index a181bc8..1fc3a21 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -354,6 +354,7 @@
batteryOffScreenOn();
}
+ @SkipPresubmit("b/185960974 flaky")
@Test
public void testCpuFreqTimes_stateTopSleeping() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
diff --git a/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java
index a21dd58..61eb173 100644
--- a/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java
@@ -52,7 +52,7 @@
mStatsRule.apply(calculator);
UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CAMERA))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA))
.isEqualTo(1000);
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
.isWithin(PRECISION).of(0.1);
diff --git a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
index 63af21d..1a99fb0f 100644
--- a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
@@ -144,7 +144,7 @@
mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
UidBatteryConsumer uidConsumer1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
- assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU))
+ assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CPU))
.isEqualTo(3333);
assertThat(uidConsumer1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
.isWithin(PRECISION).of(1.092233);
@@ -153,7 +153,7 @@
assertThat(uidConsumer1.getPackageWithHighestDrain()).isEqualTo("bar");
UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
- assertThat(uidConsumer2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU))
+ assertThat(uidConsumer2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CPU))
.isEqualTo(7777);
assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
.isWithin(PRECISION).of(2.672322);
@@ -208,7 +208,7 @@
mStatsRule.apply(calculator);
UidBatteryConsumer uidConsumer1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
- assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU))
+ assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CPU))
.isEqualTo(3333);
assertThat(uidConsumer1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
.isWithin(PRECISION).of(3.18877);
@@ -217,7 +217,7 @@
assertThat(uidConsumer1.getPackageWithHighestDrain()).isEqualTo("bar");
UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
- assertThat(uidConsumer2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU))
+ assertThat(uidConsumer2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CPU))
.isEqualTo(7777);
assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
.isWithin(PRECISION).of(7.44072);
diff --git a/core/tests/coretests/src/com/android/internal/os/FlashlightPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/FlashlightPowerCalculatorTest.java
index b7bbedd..98d5aac 100644
--- a/core/tests/coretests/src/com/android/internal/os/FlashlightPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/FlashlightPowerCalculatorTest.java
@@ -52,7 +52,7 @@
mStatsRule.apply(calculator);
UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_FLASHLIGHT))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT))
.isEqualTo(1000);
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT))
.isWithin(PRECISION).of(0.1);
diff --git a/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java
index aa066c3..7ea799f 100644
--- a/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java
@@ -56,7 +56,7 @@
mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_GNSS))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_GNSS))
.isEqualTo(1000);
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS))
.isWithin(PRECISION).of(0.1);
@@ -83,7 +83,7 @@
mStatsRule.apply(calculator);
UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_GNSS))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_GNSS))
.isEqualTo(1000);
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS))
.isWithin(PRECISION).of(2.77777);
@@ -91,7 +91,7 @@
.isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
UidBatteryConsumer consumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
- assertThat(consumer2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_GNSS))
+ assertThat(consumer2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_GNSS))
.isEqualTo(2000);
assertThat(consumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS))
.isWithin(PRECISION).of(5.55555);
diff --git a/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java
index a9800b7..2331eeb 100644
--- a/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java
@@ -48,7 +48,7 @@
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_IDLE);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_IDLE))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_IDLE))
.isEqualTo(3000);
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_IDLE))
.isWithin(PRECISION).of(0.7);
diff --git a/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java
index 71dbcdb..94e760a 100644
--- a/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java
@@ -55,7 +55,7 @@
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_MEMORY);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MEMORY))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_MEMORY))
.isEqualTo(3000);
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MEMORY))
.isWithin(PRECISION).of(0.7);
diff --git a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
index 7d829e4..93c7106 100644
--- a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
@@ -84,7 +84,7 @@
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(80 * MINUTE_IN_MS);
// 600000000 uAs * (1 mA / 1000 uA) * (1 h / 3600 s) = 166.66666 mAh
@@ -98,7 +98,7 @@
.isWithin(PRECISION).of(166.66666);
UidBatteryConsumer uid1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
- assertThat(uid1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
+ assertThat(uid1.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(20 * MINUTE_IN_MS);
// Uid1 took all of the foreground time during the first Display update.
@@ -110,7 +110,7 @@
.isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
- assertThat(uid2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
+ assertThat(uid2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(60 * MINUTE_IN_MS);
// Uid2 ran for 40 minutes out of the total 45 min of foreground time during the second
@@ -153,7 +153,7 @@
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(80 * MINUTE_IN_MS);
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isWithin(PRECISION).of(92.0);
@@ -165,7 +165,7 @@
.isWithin(PRECISION).of(92.0);
UidBatteryConsumer uid1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
- assertThat(uid1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
+ assertThat(uid1.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(20 * MINUTE_IN_MS);
// Uid1 took 20 out of the total of 80 min of foreground activity
@@ -176,7 +176,7 @@
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
- assertThat(uid2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
+ assertThat(uid2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(60 * MINUTE_IN_MS);
// Uid2 took 60 out of the total of 80 min of foreground activity
diff --git a/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java
index b50435b..74235b2 100644
--- a/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java
@@ -70,7 +70,7 @@
mStatsRule.apply(calculator);
UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SENSORS))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SENSORS))
.isEqualTo(3000);
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SENSORS))
.isWithin(PRECISION).of(0.5);
diff --git a/core/tests/coretests/src/com/android/internal/os/UserPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/UserPowerCalculatorTest.java
index 6fa1d3b..aae69d7 100644
--- a/core/tests/coretests/src/com/android/internal/os/UserPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/UserPowerCalculatorTest.java
@@ -58,16 +58,16 @@
assertThat(mStatsRule.getUserBatteryConsumer(USER1)).isNull();
assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1))
- .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)).isEqualTo(3000);
+ .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)).isEqualTo(3000);
assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1))
- .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)).isEqualTo(7000);
+ .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)).isEqualTo(7000);
assertThat(mStatsRule.getUserBatteryConsumer(USER2)).isNull();
assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID2))
- .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)).isEqualTo(5555);
+ .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)).isEqualTo(5555);
assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID2))
- .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)).isEqualTo(9999);
+ .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)).isEqualTo(9999);
}
@Test
@@ -82,19 +82,19 @@
assertThat(mStatsRule.getUserBatteryConsumer(USER1)).isNull();
assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1))
- .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)).isEqualTo(3000);
+ .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)).isEqualTo(3000);
assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1))
- .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)).isEqualTo(7000);
+ .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)).isEqualTo(7000);
assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID2))).isNull();
assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID3))
- .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)).isEqualTo(7070);
+ .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)).isEqualTo(7070);
assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID3))
- .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)).isEqualTo(11110);
+ .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)).isEqualTo(11110);
UserBatteryConsumer user2 = mStatsRule.getUserBatteryConsumer(USER2);
- assertThat(user2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO))
+ assertThat(user2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO))
.isEqualTo(15308);
- assertThat(user2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO))
+ assertThat(user2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO))
.isEqualTo(24196);
assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID1))).isNull();
@@ -130,7 +130,7 @@
protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
long durationMs = u.getAudioTurnedOnTimer().getTotalTimeLocked(rawRealtimeUs, 0);
- app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO, durationMs / 1000);
+ app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO, durationMs / 1000);
}
}
@@ -139,7 +139,7 @@
protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
long durationMs = u.getVideoTurnedOnTimer().getTotalTimeLocked(rawRealtimeUs, 0);
- app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO, durationMs / 1000);
+ app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO, durationMs / 1000);
}
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java
index 39eac49..fa0dbc7 100644
--- a/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java
@@ -52,7 +52,7 @@
mStatsRule.apply(calculator);
UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO))
.isEqualTo(1000);
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO))
.isWithin(PRECISION).of(0.1);
diff --git a/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java
index 4f71b43..9d3ed55 100644
--- a/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java
@@ -62,13 +62,13 @@
mStatsRule.apply(calculator);
UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK))
.isEqualTo(1000);
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK))
.isWithin(PRECISION).of(0.1);
UidBatteryConsumer osConsumer = mStatsRule.getUidBatteryConsumer(Process.ROOT_UID);
- assertThat(osConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK))
+ assertThat(osConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK))
.isEqualTo(5000);
assertThat(osConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK))
.isWithin(PRECISION).of(0.5);
diff --git a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
index 9349bce..4a7cf1e 100644
--- a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
@@ -87,7 +87,7 @@
mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
- assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+ assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI))
.isEqualTo(1423);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
.isWithin(PRECISION).of(0.2214666);
@@ -96,7 +96,7 @@
SystemBatteryConsumer systemConsumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
- assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+ assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI))
.isEqualTo(5577);
assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
.isWithin(PRECISION).of(1.11153);
@@ -117,7 +117,7 @@
mStatsRule.apply(calculator);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
- assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+ assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI))
.isEqualTo(1423);
/* Same ratio as in testPowerControllerBasedModel_nonMeasured but scaled by 1_000_000uC. */
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
@@ -127,7 +127,7 @@
SystemBatteryConsumer systemConsumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
- assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+ assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI))
.isEqualTo(5577);
/* Same ratio as in testPowerControllerBasedModel_nonMeasured but scaled by 1_000_000uC. */
assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
@@ -162,7 +162,7 @@
mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
- assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+ assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI))
.isEqualTo(1000);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
.isWithin(PRECISION).of(0.8231573);
@@ -171,7 +171,7 @@
SystemBatteryConsumer systemConsumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
- assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+ assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI))
.isEqualTo(2222);
assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
.isWithin(PRECISION).of(2.575000);
@@ -193,7 +193,7 @@
mStatsRule.apply(calculator);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
- assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+ assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI))
.isEqualTo(1000);
/* Same ratio as in testTimerBasedModel_nonMeasured but scaled by 1_000_000uC. */
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
@@ -203,7 +203,7 @@
SystemBatteryConsumer systemConsumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
- assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+ assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI))
.isEqualTo(2222);
/* Same ratio as in testTimerBasedModel_nonMeasured but scaled by 1_000_000uC. */
assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
diff --git a/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java b/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java
index bdaf630..4cad535 100644
--- a/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java
+++ b/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java
@@ -19,7 +19,6 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -114,30 +113,6 @@
}
@Test
- public void testRegister_FirstRegisterFails() throws RemoteException {
- AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
- AdapterStateCallback callback1 = mock(AdapterStateCallback.class);
- AdapterStateCallback callback2 = mock(AdapterStateCallback.class);
-
- // Throw a remote exception whenever first registering
- doThrow(mThrowRemoteException).when(mUwbAdapter).registerAdapterStateCallbacks(any());
-
- adapterStateListener.register(getExecutor(), callback1);
- verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
-
- // No longer throw an exception, instead succeed
- doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
-
- // Register a different callback
- adapterStateListener.register(getExecutor(), callback2);
- verify(mUwbAdapter, times(2)).registerAdapterStateCallbacks(any());
-
- // Ensure first callback was invoked again
- verifyCallbackStateChangedInvoked(callback1, 2);
- verifyCallbackStateChangedInvoked(callback2, 1);
- }
-
- @Test
public void testRegister_RegisterSameCallbackTwice() throws RemoteException {
AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
AdapterStateCallback callback = mock(AdapterStateCallback.class);
@@ -162,13 +137,6 @@
runViaExecutor();
}
- @Test
- public void testCallback_RunViaExecutor_Failure() throws RemoteException {
- // Verify that the callbacks are invoked on the executor when there is a remote exception
- doThrow(mThrowRemoteException).when(mUwbAdapter).registerAdapterStateCallbacks(any());
- runViaExecutor();
- }
-
private void runViaExecutor() {
AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
AdapterStateCallback callback = mock(AdapterStateCallback.class);
diff --git a/data/keyboards/Vendor_054c_Product_0268.kl b/data/keyboards/Vendor_054c_Product_0268.kl
index b463dd8..08d1c34 100644
--- a/data/keyboards/Vendor_054c_Product_0268.kl
+++ b/data/keyboards/Vendor_054c_Product_0268.kl
@@ -77,3 +77,11 @@
key 0x123 BUTTON_START
# PS key
key 0x2d0 BUTTON_MODE
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_0268_Version_8000.kl b/data/keyboards/Vendor_054c_Product_0268_Version_8000.kl
index 3d93f0f..d281b4b 100644
--- a/data/keyboards/Vendor_054c_Product_0268_Version_8000.kl
+++ b/data/keyboards/Vendor_054c_Product_0268_Version_8000.kl
@@ -55,3 +55,11 @@
key 0x13b BUTTON_START
# PS key
key 0x13c BUTTON_MODE
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_0268_Version_8100.kl b/data/keyboards/Vendor_054c_Product_0268_Version_8100.kl
index 3d93f0f..d281b4b 100644
--- a/data/keyboards/Vendor_054c_Product_0268_Version_8100.kl
+++ b/data/keyboards/Vendor_054c_Product_0268_Version_8100.kl
@@ -55,3 +55,11 @@
key 0x13b BUTTON_START
# PS key
key 0x13c BUTTON_MODE
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_0268_Version_8111.kl b/data/keyboards/Vendor_054c_Product_0268_Version_8111.kl
index 5fe35f7..3eafea0 100644
--- a/data/keyboards/Vendor_054c_Product_0268_Version_8111.kl
+++ b/data/keyboards/Vendor_054c_Product_0268_Version_8111.kl
@@ -55,3 +55,11 @@
key 0x13b BUTTON_START
# PS key
key 0x13c BUTTON_MODE
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Virtual.kcm b/data/keyboards/Virtual.kcm
index 9c55a2f..53308e3 100644
--- a/data/keyboards/Virtual.kcm
+++ b/data/keyboards/Virtual.kcm
@@ -25,12 +25,14 @@
label: 'A'
base: 'a'
shift, capslock: 'A'
+ shift+capslock: 'a'
}
key B {
label: 'B'
base: 'b'
shift, capslock: 'B'
+ shift+capslock: 'b'
}
key C {
@@ -39,12 +41,14 @@
shift, capslock: 'C'
alt: '\u00e7'
shift+alt: '\u00c7'
+ shift+capslock: 'c'
}
key D {
label: 'D'
base: 'd'
shift, capslock: 'D'
+ shift+capslock: 'd'
}
key E {
@@ -52,24 +56,28 @@
base: 'e'
shift, capslock: 'E'
alt: '\u0301'
+ shift+capslock: 'e'
}
key F {
label: 'F'
base: 'f'
shift, capslock: 'F'
+ shift+capslock: 'f'
}
key G {
label: 'G'
base: 'g'
shift, capslock: 'G'
+ shift+capslock: 'g'
}
key H {
label: 'H'
base: 'h'
shift, capslock: 'H'
+ shift+capslock: 'h'
}
key I {
@@ -77,30 +85,35 @@
base: 'i'
shift, capslock: 'I'
alt: '\u0302'
+ shift+capslock: 'i'
}
key J {
label: 'J'
base: 'j'
shift, capslock: 'J'
+ shift+capslock: 'j'
}
key K {
label: 'K'
base: 'k'
shift, capslock: 'K'
+ shift+capslock: 'k'
}
key L {
label: 'L'
base: 'l'
shift, capslock: 'L'
+ shift+capslock: 'l'
}
key M {
label: 'M'
base: 'm'
shift, capslock: 'M'
+ shift+capslock: 'm'
}
key N {
@@ -108,30 +121,35 @@
base: 'n'
shift, capslock: 'N'
alt: '\u0303'
+ shift+capslock: 'n'
}
key O {
label: 'O'
base: 'o'
shift, capslock: 'O'
+ shift+capslock: 'o'
}
key P {
label: 'P'
base: 'p'
shift, capslock: 'P'
+ shift+capslock: 'p'
}
key Q {
label: 'Q'
base: 'q'
shift, capslock: 'Q'
+ shift+capslock: 'q'
}
key R {
label: 'R'
base: 'r'
shift, capslock: 'R'
+ shift+capslock: 'r'
}
key S {
@@ -139,12 +157,14 @@
base: 's'
shift, capslock: 'S'
alt: '\u00df'
+ shift+capslock: 's'
}
key T {
label: 'T'
base: 't'
shift, capslock: 'T'
+ shift+capslock: 't'
}
key U {
@@ -152,36 +172,42 @@
base: 'u'
shift, capslock: 'U'
alt: '\u0308'
+ shift+capslock: 'u'
}
key V {
label: 'V'
base: 'v'
shift, capslock: 'V'
+ shift+capslock: 'v'
}
key W {
label: 'W'
base: 'w'
shift, capslock: 'W'
+ shift+capslock: 'w'
}
key X {
label: 'X'
base: 'x'
shift, capslock: 'X'
+ shift+capslock: 'x'
}
key Y {
label: 'Y'
base: 'y'
shift, capslock: 'Y'
+ shift+capslock: 'y'
}
key Z {
label: 'Z'
base: 'z'
shift, capslock: 'Z'
+ shift+capslock: 'z'
}
key 0 {
diff --git a/graphics/java/android/graphics/drawable/ColorStateListDrawable.java b/graphics/java/android/graphics/drawable/ColorStateListDrawable.java
index 20cd825..423e66c 100644
--- a/graphics/java/android/graphics/drawable/ColorStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorStateListDrawable.java
@@ -48,6 +48,12 @@
setColorStateList(colorStateList);
}
+ private ColorStateListDrawable(@NonNull ColorStateListDrawableState state) {
+ mState = state;
+ initializeColorDrawable();
+ onStateChange(getState());
+ }
+
@Override
public void draw(@NonNull Canvas canvas) {
mColorDrawable.draw(canvas);
@@ -286,11 +292,6 @@
}
}
- private ColorStateListDrawable(@NonNull ColorStateListDrawableState state) {
- mState = state;
- initializeColorDrawable();
- }
-
private void initializeColorDrawable() {
mColorDrawable = new ColorDrawable();
mColorDrawable.setCallback(this);
diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java
index e7c1081..2b4d5b4 100644
--- a/graphics/java/android/graphics/drawable/RippleShader.java
+++ b/graphics/java/android/graphics/drawable/RippleShader.java
@@ -115,7 +115,7 @@
+ " float fade = min(fadeIn, 1. - fadeOutRipple);\n"
+ " vec4 circle = in_color * (softCircle(p, center, in_maxRadius "
+ " * scaleIn, 0.2) * fade);\n"
- + " float mask = in_hasMask == 1. ? sample(in_shader).a > 0. ? 1. : 0. : 1.;\n"
+ + " float mask = in_hasMask == 1. ? sample(in_shader, p).a > 0. ? 1. : 0. : 1.;\n"
+ " return mix(circle, in_sparkleColor, sparkle) * mask;\n"
+ "}";
private static final String SHADER = SHADER_UNIFORMS + SHADER_LIB + SHADER_MAIN;
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 9298d9fc..4065bd1 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -349,15 +349,19 @@
private final Rect mTmpBounds = new Rect();
public VectorDrawable() {
- this(new VectorDrawableState(null), null);
+ this(null, null);
}
/**
* The one constructor to rule them all. This is called by all public
* constructors to set the state and initialize local properties.
*/
- private VectorDrawable(@NonNull VectorDrawableState state, @Nullable Resources res) {
- mVectorState = state;
+ private VectorDrawable(@Nullable VectorDrawableState state, @Nullable Resources res) {
+ // As the mutable, not-thread-safe native instance is stored in VectorDrawableState, we
+ // need to always do a defensive copy even if mutate() isn't called. Otherwise
+ // draw() being called on 2 different VectorDrawable instances could still hit the same
+ // underlying native object.
+ mVectorState = new VectorDrawableState(state);
updateLocalState(res);
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
index 9d8a5ef..e808c5c 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
@@ -579,7 +579,11 @@
protected final byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
throws IllegalBlockSizeException, BadPaddingException {
if (mCipher != null) {
- return mCipher.doFinal(input, inputOffset, inputLen);
+ if (input == null && inputLen == 0) {
+ return mCipher.doFinal();
+ } else {
+ return mCipher.doFinal(input, inputOffset, inputLen);
+ }
}
if (mCachedException != null) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java
index ce9be6a..a0d5b00 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java
@@ -69,21 +69,15 @@
new ResourceConfigDisplayFeatureProducer(context)
));
- mDevicePostureProducer.addDataChangedCallback(this::onDevicePostureChanged);
+ mDevicePostureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
mDisplayFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
}
- private void onDevicePostureChanged() {
- updateDeviceState(new ExtensionDeviceState(getDevicePosture()));
-
- // Trigger a change in display features as the posture will be used in place of the feature
- // state if the state is left unset by the producer.
- onDisplayFeaturesChanged();
- }
-
- private int getDevicePosture() {
+ private int getFeatureState(DisplayFeature feature) {
+ Integer featureState = feature.getState();
Optional<Integer> posture = mDevicePostureProducer.getData();
- return posture.orElse(ExtensionDeviceState.POSTURE_UNKNOWN);
+ int fallbackPosture = posture.orElse(ExtensionFoldingFeature.STATE_FLAT);
+ return featureState == null ? fallbackPosture : featureState;
}
private void onDisplayFeaturesChanged() {
@@ -115,17 +109,14 @@
Optional<List<DisplayFeature>> storedFeatures = mDisplayFeatureProducer.getData();
if (storedFeatures.isPresent()) {
- int posture = getDevicePosture();
for (DisplayFeature baseFeature : storedFeatures.get()) {
Rect featureRect = baseFeature.getRect();
rotateRectToDisplayRotation(displayId, featureRect);
transformToWindowSpaceRect(activity, featureRect);
- Integer featureState = baseFeature.getState();
-
features.add(new ExtensionFoldingFeature(featureRect, baseFeature.getType(),
- featureState == null ? posture : featureState));
+ getFeatureState(baseFeature)));
}
}
return features;
@@ -141,7 +132,6 @@
mSettingsDisplayFeatureProducer.unregisterObserversIfNeeded();
}
- onDevicePostureChanged();
onDisplayFeaturesChanged();
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/StubExtension.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/StubExtension.java
index b0895ef..6a53efee 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/StubExtension.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/StubExtension.java
@@ -31,7 +31,6 @@
private ExtensionCallback mExtensionCallback;
private final Set<Activity> mWindowLayoutChangeListenerActivities = new HashSet<>();
- private boolean mDeviceStateChangeListenerRegistered;
StubExtension() {
}
@@ -53,18 +52,6 @@
this.onListenersChanged();
}
- @Override
- public void onDeviceStateListenersChanged(boolean isEmpty) {
- this.mDeviceStateChangeListenerRegistered = !isEmpty;
- this.onListenersChanged();
- }
-
- void updateDeviceState(ExtensionDeviceState newState) {
- if (this.mExtensionCallback != null) {
- mExtensionCallback.onDeviceStateChanged(newState);
- }
- }
-
void updateWindowLayout(@NonNull Activity activity,
@NonNull ExtensionWindowLayoutInfo newLayout) {
if (this.mExtensionCallback != null) {
@@ -78,8 +65,7 @@
}
protected boolean hasListeners() {
- return !mWindowLayoutChangeListenerActivities.isEmpty()
- || mDeviceStateChangeListenerRegistered;
+ return !mWindowLayoutChangeListenerActivities.isEmpty();
}
protected abstract void onListenersChanged();
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index 7b306b0..be6652d 100644
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/libs/WindowManager/Jetpack/window-sidecar-release.aar b/libs/WindowManager/Jetpack/window-sidecar-release.aar
index 50f101d..9d6baee 100644
--- a/libs/WindowManager/Jetpack/window-sidecar-release.aar
+++ b/libs/WindowManager/Jetpack/window-sidecar-release.aar
Binary files differ
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index a138fee..e8757b5 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -52,9 +52,6 @@
when the PIP menu is shown in center. -->
<string translatable="false" name="pip_menu_bounds">"596 280 1324 690"</string>
- <!-- maximum animation duration for the icon when entering the starting window -->
- <integer name="max_starting_window_intro_icon_anim_duration">1000</integer>
-
<!-- Animation duration when exit starting window: icon going away -->
<integer name="starting_window_icon_exit_anim_duration">166</integer>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 3ced8d3..ef731235 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -178,7 +178,9 @@
<dimen name="bubble_stack_user_education_side_inset">72dp</dimen>
<!-- The width/height of the icon view on staring surface. -->
- <dimen name="starting_surface_icon_size">108dp</dimen>
+ <dimen name="starting_surface_icon_size">160dp</dimen>
+ <!-- The default width/height of the icon on the spec of adaptive icon drawable. -->
+ <dimen name="default_icon_size">108dp</dimen>
<!-- The width/height of the size compat restart button. -->
<dimen name="size_compat_button_size">48dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 4b03721..6a0f0619 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -52,6 +52,7 @@
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.PointF;
+import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -70,6 +71,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
+import android.window.WindowContainerTransaction;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
@@ -79,6 +81,8 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.common.DisplayChangeController;
+import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerCallback;
@@ -131,6 +135,7 @@
private final WindowManager mWindowManager;
private final TaskStackListenerImpl mTaskStackListener;
private final ShellTaskOrganizer mTaskOrganizer;
+ private final DisplayController mDisplayController;
// Used to post to main UI thread
private final ShellExecutor mMainExecutor;
@@ -171,25 +176,21 @@
/** Whether or not the BubbleStackView has been added to the WindowManager. */
private boolean mAddedToWindowManager = false;
- /** Last known orientation, used to detect orientation changes in {@link #onConfigChanged}. */
- private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
-
- /**
- * Last known screen density, used to detect display size changes in {@link #onConfigChanged}.
- */
+ /** Saved screen density, used to detect display size changes in {@link #onConfigChanged}. */
private int mDensityDpi = Configuration.DENSITY_DPI_UNDEFINED;
- /**
- * Last known font scale, used to detect font size changes in {@link #onConfigChanged}.
- */
+ /** Saved screen bounds, used to detect screen size changes in {@link #onConfigChanged}. **/
+ private Rect mScreenBounds = new Rect();
+
+ /** Saved font scale, used to detect font size changes in {@link #onConfigChanged}. */
private float mFontScale = 0;
- /** Last known direction, used to detect layout direction changes @link #onConfigChanged}. */
+ /** Saved direction, used to detect layout direction changes @link #onConfigChanged}. */
private int mLayoutDirection = View.LAYOUT_DIRECTION_UNDEFINED;
private boolean mInflateSynchronously;
- /** true when user is in status bar unlock shade. */
+ /** True when user is in status bar unlock shade. */
private boolean mIsStatusBarShade = true;
/**
@@ -205,6 +206,7 @@
TaskStackListenerImpl taskStackListener,
UiEventLogger uiEventLogger,
ShellTaskOrganizer organizer,
+ DisplayController displayController,
ShellExecutor mainExecutor,
Handler mainHandler) {
BubbleLogger logger = new BubbleLogger(uiEventLogger);
@@ -213,7 +215,8 @@
return new BubbleController(context, data, synchronizer, floatingContentCoordinator,
new BubbleDataRepository(context, launcherApps, mainExecutor),
statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
- logger, taskStackListener, organizer, positioner, mainExecutor, mainHandler);
+ logger, taskStackListener, organizer, positioner, displayController, mainExecutor,
+ mainHandler);
}
/**
@@ -233,6 +236,7 @@
TaskStackListenerImpl taskStackListener,
ShellTaskOrganizer organizer,
BubblePositioner positioner,
+ DisplayController displayController,
ShellExecutor mainExecutor,
Handler mainHandler) {
mContext = context;
@@ -256,6 +260,7 @@
mBubbleData = data;
mSavedBubbleKeysPerUser = new SparseSetArray<>();
mBubbleIconFactory = new BubbleIconFactory(context);
+ mDisplayController = displayController;
}
public void initialize() {
@@ -287,7 +292,6 @@
e.printStackTrace();
}
-
mBubbleData.setCurrentUserId(mCurrentUserId);
mTaskOrganizer.addLocusIdListener((taskId, locus, visible) ->
@@ -366,6 +370,23 @@
}
}
});
+
+ mDisplayController.addDisplayChangingController(
+ new DisplayChangeController.OnDisplayChangingListener() {
+ @Override
+ public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
+ WindowContainerTransaction t) {
+ // This is triggered right before the rotation is applied
+ if (fromRotation != toRotation) {
+ mBubblePositioner.setRotation(toRotation);
+ if (mStackView != null) {
+ // Layout listener set on stackView will update the positioner
+ // once the rotation is applied
+ mStackView.onOrientationChanged();
+ }
+ }
+ }
+ });
}
@VisibleForTesting
@@ -585,7 +606,7 @@
mStackView.addView(mBubbleScrim);
mWindowManager.addView(mStackView, mWmLayoutParams);
// Position info is dependent on us being attached to a window
- mBubblePositioner.update(mOrientation);
+ mBubblePositioner.update();
} catch (IllegalStateException e) {
// This means the stack has already been added. This shouldn't happen...
e.printStackTrace();
@@ -682,16 +703,13 @@
private void onConfigChanged(Configuration newConfig) {
if (mBubblePositioner != null) {
- // This doesn't trigger any changes, always update it
- mBubblePositioner.update(newConfig.orientation);
+ mBubblePositioner.update();
}
if (mStackView != null && newConfig != null) {
- if (newConfig.orientation != mOrientation) {
- mOrientation = newConfig.orientation;
- mStackView.onOrientationChanged();
- }
- if (newConfig.densityDpi != mDensityDpi) {
+ if (newConfig.densityDpi != mDensityDpi
+ || !newConfig.windowConfiguration.getBounds().equals(mScreenBounds)) {
mDensityDpi = newConfig.densityDpi;
+ mScreenBounds.set(newConfig.windowConfiguration.getBounds());
mBubbleIconFactory = new BubbleIconFactory(mContext);
mStackView.onDisplaySizeChanged();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 1562e4b..a81c2d8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -20,13 +20,13 @@
import android.annotation.IntDef;
import android.content.Context;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;
+import android.view.Surface;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -65,7 +65,7 @@
private Context mContext;
private WindowManager mWindowManager;
private Rect mPositionRect;
- private int mOrientation;
+ private @Surface.Rotation int mRotation = Surface.ROTATION_0;
private Insets mInsets;
private int mBubbleSize;
@@ -82,14 +82,18 @@
public BubblePositioner(Context context, WindowManager windowManager) {
mContext = context;
mWindowManager = windowManager;
- update(Configuration.ORIENTATION_UNDEFINED);
+ update();
+ }
+
+ public void setRotation(int rotation) {
+ mRotation = rotation;
}
/**
- * Updates orientation, available space, and inset information. Call this when config changes
+ * Available space and inset information. Call this when config changes
* occur or when added to a window.
*/
- public void update(int orientation) {
+ public void update() {
WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
if (windowMetrics == null) {
return;
@@ -102,12 +106,12 @@
if (BubbleDebugConfig.DEBUG_POSITIONER) {
Log.w(TAG, "update positioner:"
- + " landscape= " + (orientation == Configuration.ORIENTATION_LANDSCAPE)
+ + " rotation= " + mRotation
+ " insets: " + insets
+ " bounds: " + windowMetrics.getBounds()
+ " showingInTaskbar: " + mShowingInTaskbar);
}
- updateInternal(orientation, insets, windowMetrics.getBounds());
+ updateInternal(mRotation, insets, windowMetrics.getBounds());
}
/**
@@ -122,12 +126,12 @@
mTaskbarIconSize = iconSize;
mTaskbarPosition = taskbarPosition;
mTaskbarSize = taskbarSize;
- update(mOrientation);
+ update();
}
@VisibleForTesting
- public void updateInternal(int orientation, Insets insets, Rect bounds) {
- mOrientation = orientation;
+ public void updateInternal(int rotation, Insets insets, Rect bounds) {
+ mRotation = rotation;
mInsets = insets;
mPositionRect = new Rect(bounds);
@@ -189,7 +193,7 @@
* @return whether the device is in landscape orientation.
*/
public boolean isLandscape() {
- return mOrientation == Configuration.ORIENTATION_LANDSCAPE;
+ return mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270;
}
/**
@@ -200,8 +204,7 @@
* to the left or right side.
*/
public boolean showBubblesVertically() {
- return mOrientation == Configuration.ORIENTATION_LANDSCAPE
- || mShowingInTaskbar;
+ return isLandscape() || mShowingInTaskbar;
}
/** Size of the bubble account for badge & dot. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 64bd245..6719d74 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -884,6 +884,7 @@
mOrientationChangedListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ mPositioner.update();
onDisplaySizeChanged();
mExpandedAnimationController.updateResources();
mStackAnimationController.updateResources();
@@ -1214,11 +1215,12 @@
updateExpandedViewTheme();
}
- /** Respond to the phone being rotated by repositioning the stack and hiding any flyouts. */
+ /**
+ * Respond to the phone being rotated by repositioning the stack and hiding any flyouts.
+ * This is called prior to the rotation occurring, any values that should be updated
+ * based on the new rotation should occur in {@link #mOrientationChangedListener}.
+ */
public void onOrientationChanged() {
- Resources res = getContext().getResources();
- mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
-
mRelativeStackPositionBeforeRotation = new RelativeStackPosition(
mPositioner.getRestingPosition(),
mStackAnimationController.getAllowableStackPositionRegion());
@@ -1261,6 +1263,10 @@
mStackAnimationController.updateResources();
mDismissView.updateResources();
mMagneticTarget.setMagneticFieldRadiusPx(mBubbleSize * 2);
+ mStackAnimationController.setStackPosition(
+ new RelativeStackPosition(
+ mPositioner.getRestingPosition(),
+ mStackAnimationController.getAllowableStackPositionRegion()));
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 58b3de4..04ec391 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -218,7 +218,7 @@
OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor);
OneHandedState transitionState = new OneHandedState();
OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context,
- windowManager, mainExecutor);
+ displayLayout, windowManager, mainExecutor);
OneHandedAnimationController animationController =
new OneHandedAnimationController(context);
OneHandedTouchHandler touchHandler = new OneHandedTouchHandler(timeoutHandler,
@@ -453,6 +453,7 @@
final DisplayLayout newDisplayLayout = mDisplayController.getDisplayLayout(displayId);
mDisplayAreaOrganizer.setDisplayLayout(newDisplayLayout);
mGestureHandler.onDisplayChanged(newDisplayLayout);
+ mTutorialHandler.onDisplayChanged(newDisplayLayout);
}
private ContentObserver getObserver(Runnable onChangeRunnable) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index 4b4d934..6bd9603 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -81,14 +81,6 @@
@Override
public void onOneHandedAnimationStart(
OneHandedAnimationController.OneHandedTransitionAnimator animator) {
- final boolean isEntering = animator.getTransitionDirection()
- == TRANSITION_DIRECTION_TRIGGER;
- if (!mTransitionCallbacks.isEmpty()) {
- for (int i = mTransitionCallbacks.size() - 1; i >= 0; i--) {
- final OneHandedTransitionCallback cb = mTransitionCallbacks.get(i);
- cb.onStartTransition(isEntering);
- }
- }
}
@Override
@@ -270,12 +262,11 @@
mLastVisualDisplayBounds.offsetTo(0,
direction == TRANSITION_DIRECTION_TRIGGER ? offset : 0);
for (int i = mTransitionCallbacks.size() - 1; i >= 0; i--) {
- final OneHandedTransitionCallback cb = mTransitionCallbacks.get(i);
- cb.onStartTransition(false /* isTransitioning */);
+ final OneHandedTransitionCallback callback = mTransitionCallbacks.get(i);
if (direction == TRANSITION_DIRECTION_TRIGGER) {
- cb.onStartFinished(getLastVisualDisplayBounds());
+ callback.onStartFinished(getLastVisualDisplayBounds());
} else {
- cb.onStopFinished(getLastVisualDisplayBounds());
+ callback.onStopFinished(getLastVisualDisplayBounds());
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTransitionCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTransitionCallback.java
index e829186..3af7c4b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTransitionCallback.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTransitionCallback.java
@@ -24,12 +24,6 @@
*/
public interface OneHandedTransitionCallback {
/**
- * Called when one handed mode entering or exiting transition starting
- */
- default void onStartTransition(boolean isEntering) {
- }
-
- /**
* Called when start one handed transition finished
*/
default void onStartFinished(Rect bounds) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
index b445917..7a3f34d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
@@ -33,6 +33,7 @@
import androidx.annotation.NonNull;
import com.android.wm.shell.R;
+import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import java.io.PrintWriter;
@@ -50,9 +51,10 @@
private static final int MAX_TUTORIAL_SHOW_COUNT = 2;
private final WindowManager mWindowManager;
private final String mPackageName;
- private final Rect mDisplaySize;
+ private final float mTutorialHeightRatio;
private Context mContext;
+ private Rect mDisplayBounds;
private View mTutorialView;
private ContentResolver mContentResolver;
private boolean mCanShowTutorial;
@@ -94,23 +96,22 @@
}
};
- public OneHandedTutorialHandler(Context context, WindowManager windowManager,
- ShellExecutor mainExecutor) {
+ public OneHandedTutorialHandler(Context context, DisplayLayout displayLayout,
+ WindowManager windowManager, ShellExecutor mainExecutor) {
mContext = context;
mWindowManager = windowManager;
- mDisplaySize = windowManager.getCurrentWindowMetrics().getBounds();
mPackageName = context.getPackageName();
mContentResolver = context.getContentResolver();
- mCanShowTutorial = (Settings.Secure.getInt(mContentResolver,
- Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0) >= MAX_TUTORIAL_SHOW_COUNT)
- ? false : true;
- mIsOneHandedMode = false;
final float offsetPercentageConfig = context.getResources().getFraction(
R.fraction.config_one_handed_offset, 1, 1);
final int sysPropPercentageConfig = SystemProperties.getInt(
ONE_HANDED_MODE_OFFSET_PERCENTAGE, Math.round(offsetPercentageConfig * 100.0f));
- mTutorialAreaHeight = Math.round(
- mDisplaySize.height() * (sysPropPercentageConfig / 100.0f));
+ mTutorialHeightRatio = sysPropPercentageConfig / 100.0f;
+ onDisplayChanged(displayLayout);
+ mCanShowTutorial = (Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0) >= MAX_TUTORIAL_SHOW_COUNT)
+ ? false : true;
+ mIsOneHandedMode = false;
mainExecutor.execute(() -> {
recreateTutorialView(mContext);
@@ -131,6 +132,20 @@
mTriggerState = ONE_HANDED_TRIGGER_STATE.UNSET;
}
+ /**
+ * Called when onDisplayAdded() or onDisplayRemoved() callback
+ * @param displayLayout The latest {@link DisplayLayout} representing current displayId
+ */
+ public void onDisplayChanged(DisplayLayout displayLayout) {
+ // Ensure the mDisplayBounds is portrait, due to OHM only support on portrait
+ if (displayLayout.height() > displayLayout.width()) {
+ mDisplayBounds = new Rect(0, 0, displayLayout.width(), displayLayout.height());
+ } else {
+ mDisplayBounds = new Rect(0, 0, displayLayout.height(), displayLayout.width());
+ }
+ mTutorialAreaHeight = Math.round(mDisplayBounds.height() * mTutorialHeightRatio);
+ }
+
private void recreateTutorialView(Context context) {
mTutorialView = LayoutInflater.from(context).inflate(R.layout.one_handed_tutorial,
null);
@@ -190,7 +205,7 @@
*/
private WindowManager.LayoutParams getTutorialTargetLayoutParams() {
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- mDisplaySize.width(), mTutorialAreaHeight, 0, 0,
+ mDisplayBounds.width(), mTutorialAreaHeight, 0, 0,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
@@ -207,8 +222,8 @@
pw.println(TAG + " states: ");
pw.print(innerPrefix + "mTriggerState=");
pw.println(mTriggerState);
- pw.print(innerPrefix + "mDisplaySize=");
- pw.println(mDisplaySize);
+ pw.print(innerPrefix + "mDisplayBounds=");
+ pw.println(mDisplayBounds);
pw.print(innerPrefix + "mTutorialAreaHeight=");
pw.println(mTutorialAreaHeight);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 8ac9a7a..ca05ff4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -427,35 +427,43 @@
Rect baseValue, Rect startValue, Rect endValue, Rect sourceHintRect,
@PipAnimationController.TransitionDirection int direction, float startingAngle,
@Surface.Rotation int rotationDelta) {
+ final boolean isOutPipDirection = isOutPipDirection(direction);
+
// Just for simplicity we'll interpolate between the source rect hint insets and empty
// insets to calculate the window crop
final Rect initialSourceValue;
- if (isOutPipDirection(direction)) {
+ if (isOutPipDirection) {
initialSourceValue = new Rect(endValue);
} else {
initialSourceValue = new Rect(baseValue);
}
+ final Rect rotatedEndRect;
+ final Rect lastEndRect;
+ final Rect initialContainerRect;
+ if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) {
+ lastEndRect = new Rect(endValue);
+ rotatedEndRect = new Rect(endValue);
+ // Rotate the end bounds according to the rotation delta because the display will
+ // be rotated to the same orientation.
+ rotateBounds(rotatedEndRect, initialSourceValue, rotationDelta);
+ // Use the rect that has the same orientation as the hint rect.
+ initialContainerRect = isOutPipDirection ? rotatedEndRect : initialSourceValue;
+ } else {
+ rotatedEndRect = lastEndRect = null;
+ initialContainerRect = initialSourceValue;
+ }
+
final Rect sourceHintRectInsets;
if (sourceHintRect == null) {
sourceHintRectInsets = null;
} else {
- sourceHintRectInsets = new Rect(sourceHintRect.left - initialSourceValue.left,
- sourceHintRect.top - initialSourceValue.top,
- initialSourceValue.right - sourceHintRect.right,
- initialSourceValue.bottom - sourceHintRect.bottom);
+ sourceHintRectInsets = new Rect(sourceHintRect.left - initialContainerRect.left,
+ sourceHintRect.top - initialContainerRect.top,
+ initialContainerRect.right - sourceHintRect.right,
+ initialContainerRect.bottom - sourceHintRect.bottom);
}
- final Rect sourceInsets = new Rect(0, 0, 0, 0);
-
- final Rect rotatedEndRect;
- if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) {
- // Rotate the end bounds according to the rotation delta because the display will
- // be rotated to the same orientation.
- rotatedEndRect = new Rect(endValue);
- rotateBounds(rotatedEndRect, endValue, rotationDelta);
- } else {
- rotatedEndRect = null;
- }
+ final Rect zeroInsets = new Rect(0, 0, 0, 0);
// construct new Rect instances in case they are recycled
return new PipTransitionAnimator<Rect>(taskInfo, leash, ANIM_TYPE_BOUNDS,
@@ -472,8 +480,8 @@
final Rect end = getEndValue();
if (rotatedEndRect != null) {
// Animate the bounds in a different orientation. It only happens when
- // leaving PiP to fullscreen.
- applyRotation(tx, leash, fraction, start, end, rotatedEndRect);
+ // switching between PiP and fullscreen.
+ applyRotation(tx, leash, fraction, start, end);
return;
}
Rect bounds = mRectEvaluator.evaluate(fraction, start, end);
@@ -481,20 +489,13 @@
setCurrentValue(bounds);
if (inScaleTransition() || sourceHintRect == null) {
- if (isOutPipDirection(direction)) {
+ if (isOutPipDirection) {
getSurfaceTransactionHelper().scale(tx, leash, end, bounds);
} else {
getSurfaceTransactionHelper().scale(tx, leash, base, bounds, angle);
}
} else {
- final Rect insets;
- if (isOutPipDirection(direction)) {
- insets = mInsetsEvaluator.evaluate(fraction, sourceHintRectInsets,
- sourceInsets);
- } else {
- insets = mInsetsEvaluator.evaluate(fraction, sourceInsets,
- sourceHintRectInsets);
- }
+ final Rect insets = computeInsets(fraction);
getSurfaceTransactionHelper().scaleAndCrop(tx, leash,
initialSourceValue, bounds, insets);
}
@@ -502,9 +503,17 @@
}
private void applyRotation(SurfaceControl.Transaction tx, SurfaceControl leash,
- float fraction, Rect start, Rect end, Rect rotatedEndRect) {
+ float fraction, Rect start, Rect end) {
+ if (!end.equals(lastEndRect)) {
+ // If the end bounds are changed during animating (e.g. shelf height), the
+ // rotated end bounds also need to be updated.
+ rotatedEndRect.set(endValue);
+ rotateBounds(rotatedEndRect, initialSourceValue, rotationDelta);
+ lastEndRect.set(end);
+ }
final Rect bounds = mRectEvaluator.evaluate(fraction, start, rotatedEndRect);
setCurrentValue(bounds);
+ final Rect insets = computeInsets(fraction);
final float degree, x, y;
if (rotationDelta == ROTATION_90) {
degree = 90 * fraction;
@@ -515,11 +524,21 @@
x = fraction * (end.left - start.left) + start.left;
y = fraction * (end.bottom - start.top) + start.top;
}
- getSurfaceTransactionHelper().rotateAndScaleWithCrop(tx, leash, bounds,
- rotatedEndRect, degree, x, y);
+ getSurfaceTransactionHelper().rotateAndScaleWithCrop(tx, leash,
+ initialContainerRect, bounds, insets, degree, x, y, isOutPipDirection,
+ rotationDelta == ROTATION_270 /* clockwise */);
tx.apply();
}
+ private Rect computeInsets(float fraction) {
+ if (sourceHintRectInsets == null) {
+ return zeroInsets;
+ }
+ final Rect startRect = isOutPipDirection ? sourceHintRectInsets : zeroInsets;
+ final Rect endRect = isOutPipDirection ? zeroInsets : sourceHintRectInsets;
+ return mInsetsEvaluator.evaluate(fraction, startRect, endRect);
+ }
+
@Override
void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
getSurfaceTransactionHelper()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index 3dd97f5..2b79539 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -137,23 +137,41 @@
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
*/
public PipSurfaceTransactionHelper rotateAndScaleWithCrop(SurfaceControl.Transaction tx,
- SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, float degrees,
- float positionX, float positionY) {
+ SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, Rect insets,
+ float degrees, float positionX, float positionY, boolean isExpanding,
+ boolean clockwise) {
mTmpDestinationRect.set(sourceBounds);
- final int dw = destinationBounds.width();
- final int dh = destinationBounds.height();
+ mTmpDestinationRect.inset(insets);
+ final int srcW = mTmpDestinationRect.width();
+ final int srcH = mTmpDestinationRect.height();
+ final int destW = destinationBounds.width();
+ final int destH = destinationBounds.height();
// Scale by the short side so there won't be empty area if the aspect ratio of source and
// destination are different.
- final float scale = dw <= dh
- ? (float) sourceBounds.width() / dw
- : (float) sourceBounds.height() / dh;
+ final float scale = srcW <= srcH ? (float) destW / srcW : (float) destH / srcH;
+ final Rect crop = mTmpDestinationRect;
+ crop.set(0, 0, destW, destH);
// Inverse scale for crop to fit in screen coordinates.
- mTmpDestinationRect.scale(1 / scale);
- mTmpTransform.setRotate(degrees);
- mTmpTransform.postScale(scale, scale);
+ crop.scale(1 / scale);
+ crop.offset(insets.left, insets.top);
+ if (isExpanding) {
+ // Expand bounds (shrink insets) in source orientation.
+ positionX -= insets.left * scale;
+ positionY -= insets.top * scale;
+ } else {
+ // Shrink bounds (expand insets) in destination orientation.
+ if (clockwise) {
+ positionX -= insets.top * scale;
+ positionY -= insets.left * scale;
+ } else {
+ positionX += insets.top * scale;
+ positionY += insets.left * scale;
+ }
+ }
+ mTmpTransform.setScale(scale, scale);
+ mTmpTransform.postRotate(degrees);
mTmpTransform.postTranslate(positionX, positionY);
- tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
- .setWindowCrop(leash, mTmpDestinationRect.width(), mTmpDestinationRect.height());
+ tx.setMatrix(leash, mTmpTransform, mTmpFloat9).setWindowCrop(leash, crop);
return this;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index e66be66..4ce6c9e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -20,6 +20,8 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.util.RotationUtils.deltaRotation;
+import static android.util.RotationUtils.rotateBounds;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP;
import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
@@ -50,8 +52,10 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.util.Log;
import android.util.Rational;
import android.view.Display;
@@ -94,6 +98,12 @@
DisplayController.OnDisplaysChangedListener {
private static final String TAG = PipTaskOrganizer.class.getSimpleName();
private static final boolean DEBUG = false;
+ /**
+ * The alpha type is set for swiping to home. But the swiped task may not enter PiP. And if
+ * another task enters PiP by non-swipe ways, e.g. call API in foreground or switch to 3-button
+ * navigation, then the alpha type is unexpected.
+ */
+ private static final int ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS = 1000;
// Not a complete set of states but serves what we want right now.
private enum State {
@@ -127,6 +137,7 @@
}
}
+ private final Context mContext;
private final SyncTransactionQueue mSyncTransactionQueue;
private final PipBoundsState mPipBoundsState;
private final PipBoundsAlgorithm mPipBoundsAlgorithm;
@@ -160,8 +171,20 @@
public void onPipAnimationEnd(TaskInfo taskInfo, SurfaceControl.Transaction tx,
PipAnimationController.PipTransitionAnimator animator) {
final int direction = animator.getTransitionDirection();
- finishResize(tx, animator.getDestinationBounds(), direction,
- animator.getAnimationType());
+ final int animationType = animator.getAnimationType();
+ final Rect destinationBounds = animator.getDestinationBounds();
+ if (mWaitForFixedRotation && animationType == ANIM_TYPE_BOUNDS
+ && direction == TRANSITION_DIRECTION_TO_PIP) {
+ // Notify the display to continue the deferred orientation change.
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.scheduleFinishEnterPip(mToken, destinationBounds);
+ mTaskOrganizer.applyTransaction(wct);
+ // The final task bounds will be applied by onFixedRotationFinished so that all
+ // coordinates are in new rotation.
+ mDeferredAnimEndTransaction = tx;
+ return;
+ }
+ finishResize(tx, destinationBounds, direction, animationType);
sendOnPipTransitionFinished(direction);
if (direction == TRANSITION_DIRECTION_TO_PIP) {
// TODO (b//169221267): Add jank listener for transactions without buffer updates.
@@ -186,10 +209,18 @@
private SurfaceControl mLeash;
private State mState = State.UNDEFINED;
private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
+ private long mLastOneShotAlphaAnimationTime;
private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
private PictureInPictureParams mPictureInPictureParams;
private IntConsumer mOnDisplayIdChangeCallback;
+ /**
+ * The end transaction of PiP animation for switching between PiP and fullscreen with
+ * orientation change. The transaction should be applied after the display is rotated.
+ */
+ private SurfaceControl.Transaction mDeferredAnimEndTransaction;
+ /** Whether the existing PiP is hidden by alpha. */
+ private boolean mHasFadeOut;
/**
* If set to {@code true}, the entering animation will be skipped and we will wait for
@@ -203,6 +234,8 @@
*/
private @Surface.Rotation int mNextRotation;
+ private @Surface.Rotation int mCurrentRotation;
+
/**
* If set to {@code true}, no entering PiP transition would be kicked off and most likely
* it's due to the fact that Launcher is handling the transition directly when swiping
@@ -224,6 +257,7 @@
@NonNull PipUiEventLogger pipUiEventLogger,
@NonNull ShellTaskOrganizer shellTaskOrganizer,
@ShellMainThread ShellExecutor mainExecutor) {
+ mContext = context;
mSyncTransactionQueue = syncTransactionQueue;
mPipBoundsState = pipBoundsState;
mPipBoundsAlgorithm = boundsHandler;
@@ -261,10 +295,6 @@
return mState.isInPip();
}
- public boolean isDeferringEnterPipAnimation() {
- return mState.isInPip() && mWaitForFixedRotation;
- }
-
/**
* Returns whether the entry animation is waiting to be started.
*/
@@ -286,6 +316,9 @@
*/
public void setOneShotAnimationType(@PipAnimationController.AnimationType int animationType) {
mOneShotAnimationType = animationType;
+ if (animationType == ANIM_TYPE_ALPHA) {
+ mLastOneShotAlphaAnimationTime = SystemClock.uptimeMillis();
+ }
}
/**
@@ -297,9 +330,6 @@
mInSwipePipToHomeTransition = true;
sendOnPipTransitionStarted(TRANSITION_DIRECTION_TO_PIP);
setBoundsStateForEntry(componentName, pictureInPictureParams, activityInfo);
- // disable the conflicting transaction from fixed rotation, see also
- // onFixedRotationStarted and onFixedRotationFinished
- mWaitForFixedRotation = false;
return mPipBoundsAlgorithm.getEntryDestinationBounds();
}
@@ -355,6 +385,9 @@
: WINDOWING_MODE_FULLSCREEN);
wct.setBounds(mToken, destinationBounds);
wct.setBoundsChangeTransaction(mToken, tx);
+ // Set the exiting state first so if there is fixed rotation later, the running animation
+ // won't be interrupted by alpha animation for existing PiP.
+ mState = State.EXITING_PIP;
mSyncTransactionQueue.queue(wct);
mSyncTransactionQueue.runInSync(t -> {
// Make sure to grab the latest source hint rect as it could have been
@@ -362,9 +395,8 @@
final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
mPictureInPictureParams, destinationBounds);
final PipAnimationController.PipTransitionAnimator<?> animator =
- scheduleAnimateResizePip(mPipBoundsState.getBounds(), destinationBounds,
- 0 /* startingAngle */, sourceHintRect, direction,
- animationDurationMs, null /* updateBoundsCallback */);
+ animateResizePip(mPipBoundsState.getBounds(), destinationBounds, sourceHintRect,
+ direction, animationDurationMs, 0 /* startingAngle */);
if (animator != null) {
// Even though the animation was started above, re-apply the transaction for the
// first frame using the SurfaceControl.Transaction supplied by the
@@ -374,7 +406,6 @@
// hint during expansion that causes a visible jank/flash. See b/184166183.
animator.applySurfaceControlTransaction(mLeash, t, FRACTION_START);
}
- mState = State.EXITING_PIP;
});
}
@@ -447,29 +478,22 @@
}
if (mInSwipePipToHomeTransition) {
- final Rect destinationBounds = mPipBoundsState.getBounds();
- final SurfaceControl.Transaction tx =
- mSurfaceControlTransactionFactory.getTransaction();
- mSurfaceTransactionHelper.resetScale(tx, mLeash, destinationBounds);
- mSurfaceTransactionHelper.crop(tx, mLeash, destinationBounds);
- // animation is finished in the Launcher and here we directly apply the final touch.
- applyEnterPipSyncTransaction(destinationBounds, () -> {
- // ensure menu's settled in its final bounds first
- finishResizeForMenu(destinationBounds);
- sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
- }, tx);
- mInSwipePipToHomeTransition = false;
+ if (!mWaitForFixedRotation) {
+ onEndOfSwipePipToHomeTransition();
+ } else {
+ Log.d(TAG, "Defer onTaskAppeared-SwipePipToHome until end of fixed rotation.");
+ }
return;
}
+ if (mOneShotAnimationType == ANIM_TYPE_ALPHA
+ && SystemClock.uptimeMillis() - mLastOneShotAlphaAnimationTime
+ > ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS) {
+ Log.d(TAG, "Alpha animation is expired. Use bounds animation.");
+ mOneShotAnimationType = ANIM_TYPE_BOUNDS;
+ }
if (mWaitForFixedRotation) {
- if (DEBUG) Log.d(TAG, "Defer entering PiP animation, fixed rotation is ongoing");
- // if deferred, hide the surface till fixed rotation is completed
- final SurfaceControl.Transaction tx =
- mSurfaceControlTransactionFactory.getTransaction();
- tx.setAlpha(mLeash, 0f);
- tx.show(mLeash);
- tx.apply();
+ onTaskAppearedWithFixedRotation();
return;
}
@@ -500,6 +524,27 @@
}
}
+ private void onTaskAppearedWithFixedRotation() {
+ if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+ Log.d(TAG, "Defer entering PiP alpha animation, fixed rotation is ongoing");
+ // If deferred, hide the surface till fixed rotation is completed.
+ final SurfaceControl.Transaction tx =
+ mSurfaceControlTransactionFactory.getTransaction();
+ tx.setAlpha(mLeash, 0f);
+ tx.show(mLeash);
+ tx.apply();
+ mOneShotAnimationType = ANIM_TYPE_BOUNDS;
+ return;
+ }
+ final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
+ final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
+ mPictureInPictureParams, currentBounds);
+ final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
+ animateResizePip(currentBounds, destinationBounds, sourceHintRect,
+ TRANSITION_DIRECTION_TO_PIP, mEnterAnimationDuration, 0 /* startingAngle */);
+ mState = State.ENTERING_PIP;
+ }
+
/**
* Called when the display rotation handling is skipped (e.g. when rotation happens while in
* the middle of an entry transition).
@@ -536,6 +581,20 @@
}, null /* boundsChangeTransaction */);
}
+ private void onEndOfSwipePipToHomeTransition() {
+ final Rect destinationBounds = mPipBoundsState.getBounds();
+ final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
+ mSurfaceTransactionHelper.resetScale(tx, mLeash, destinationBounds);
+ mSurfaceTransactionHelper.crop(tx, mLeash, destinationBounds);
+ // The animation is finished in the Launcher and here we directly apply the final touch.
+ applyEnterPipSyncTransaction(destinationBounds, () -> {
+ // Ensure menu's settled in its final bounds first.
+ finishResizeForMenu(destinationBounds);
+ sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
+ }, tx);
+ mInSwipePipToHomeTransition = false;
+ }
+
private void applyEnterPipSyncTransaction(Rect destinationBounds, Runnable runnable,
@Nullable SurfaceControl.Transaction boundsChangeTransaction) {
// PiP menu is attached late in the process here to avoid any artifacts on the leash
@@ -547,7 +606,6 @@
if (boundsChangeTransaction != null) {
wct.setBoundsChangeTransaction(mToken, boundsChangeTransaction);
}
- wct.scheduleFinishEnterPip(mToken, destinationBounds);
mSyncTransactionQueue.queue(wct);
if (runnable != null) {
mSyncTransactionQueue.runInSync(t -> runnable.run());
@@ -600,7 +658,7 @@
Log.wtf(TAG, "Unrecognized token: " + token);
return;
}
- mWaitForFixedRotation = false;
+ clearWaitForFixedRotation();
mInSwipePipToHomeTransition = false;
mPictureInPictureParams = null;
mState = State.UNDEFINED;
@@ -617,8 +675,10 @@
@Override
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken");
- if (mState != State.ENTERED_PIP) {
+ if (mState != State.ENTERED_PIP && mState != State.EXITING_PIP) {
Log.d(TAG, "Defer onTaskInfoChange in current state: " + mState);
+ // Defer applying PiP parameters if the task is entering PiP to avoid disturbing
+ // the animation.
mDeferredTaskInfo = info;
return;
}
@@ -648,16 +708,60 @@
public void onFixedRotationStarted(int displayId, int newRotation) {
mNextRotation = newRotation;
mWaitForFixedRotation = true;
+
+ if (mState.isInPip()) {
+ // Fade out the existing PiP to avoid jump cut during seamless rotation.
+ fadeExistingPip(false /* show */);
+ }
}
@Override
public void onFixedRotationFinished(int displayId) {
- if (mWaitForFixedRotation && mState.isInPip()) {
- final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
- // schedule a regular animation to ensure all the callbacks are still being sent
- enterPipWithAlphaAnimation(destinationBounds, 0 /* durationMs */);
+ if (!mWaitForFixedRotation) {
+ return;
}
+ if (mState == State.TASK_APPEARED) {
+ if (mInSwipePipToHomeTransition) {
+ onEndOfSwipePipToHomeTransition();
+ } else {
+ // Schedule a regular animation to ensure all the callbacks are still being sent.
+ enterPipWithAlphaAnimation(mPipBoundsAlgorithm.getEntryDestinationBounds(),
+ mEnterAnimationDuration);
+ }
+ } else if (mState == State.ENTERED_PIP && mHasFadeOut) {
+ fadeExistingPip(true /* show */);
+ } else if (mState == State.ENTERING_PIP && mDeferredAnimEndTransaction != null) {
+ final PipAnimationController.PipTransitionAnimator<?> animator =
+ mPipAnimationController.getCurrentAnimator();
+ final Rect destinationBounds = animator.getDestinationBounds();
+ mPipBoundsState.setBounds(destinationBounds);
+ applyEnterPipSyncTransaction(destinationBounds, () -> {
+ finishResizeForMenu(destinationBounds);
+ sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
+ }, mDeferredAnimEndTransaction);
+ }
+ clearWaitForFixedRotation();
+ }
+
+ private void fadeExistingPip(boolean show) {
+ final float alphaStart = show ? 0 : 1;
+ final float alphaEnd = show ? 1 : 0;
+ mPipAnimationController
+ .getAnimator(mTaskInfo, mLeash, mPipBoundsState.getBounds(), alphaStart, alphaEnd)
+ .setTransitionDirection(TRANSITION_DIRECTION_SAME)
+ .setDuration(show ? mEnterAnimationDuration : mExitAnimationDuration)
+ .start();
+ mHasFadeOut = !show;
+ }
+
+ private void clearWaitForFixedRotation() {
mWaitForFixedRotation = false;
+ mDeferredAnimEndTransaction = null;
+ }
+
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ mCurrentRotation = newConfig.windowConfiguration.getRotation();
}
/**
@@ -686,7 +790,11 @@
mPipAnimationController.getCurrentAnimator();
if (animator == null || !animator.isRunning()
|| animator.getTransitionDirection() != TRANSITION_DIRECTION_TO_PIP) {
- if (mState.isInPip() && fromRotation && !mWaitForFixedRotation) {
+ final boolean rotatingPip = mState.isInPip() && fromRotation;
+ if (rotatingPip && mWaitForFixedRotation && mHasFadeOut) {
+ // The position will be used by fade-in animation when the fixed rotation is done.
+ mPipBoundsState.setBounds(destinationBoundsOut);
+ } else if (rotatingPip) {
// Update bounds state to final destination first. It's important to do this
// before finishing & cancelling the transition animation so that the MotionHelper
// bounds are synchronized to the destination bounds when the animation ends.
@@ -737,7 +845,17 @@
final Rect newDestinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
if (newDestinationBounds.equals(currentDestinationBounds)) return;
if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) {
- animator.updateEndValue(newDestinationBounds);
+ if (mWaitForFixedRotation) {
+ // The new destination bounds are in next rotation (DisplayLayout has been rotated
+ // in computeRotatedBounds). The animation runs in previous rotation so the end
+ // bounds need to be transformed.
+ final Rect displayBounds = mPipBoundsState.getDisplayBounds();
+ final Rect rotatedEndBounds = new Rect(newDestinationBounds);
+ rotateBounds(rotatedEndBounds, displayBounds, mNextRotation, mCurrentRotation);
+ animator.updateEndValue(rotatedEndBounds);
+ } else {
+ animator.updateEndValue(newDestinationBounds);
+ }
}
animator.setDestinationBounds(newDestinationBounds);
destinationBoundsOut.set(newDestinationBounds);
@@ -1050,7 +1168,6 @@
// activity windowing mode set by WM, and set the task bounds to the final bounds
taskBounds = destinationBounds;
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
- wct.scheduleFinishEnterPip(mToken, destinationBounds);
} else if (isOutPipDirection(direction)) {
// If we are animating to fullscreen or split screen, then we need to reset the
// override bounds on the task to ensure that the task "matches" the parent's bounds.
@@ -1096,8 +1213,12 @@
return null;
}
final int rotationDelta = mWaitForFixedRotation
- ? ((mNextRotation - mPipBoundsState.getDisplayLayout().rotation()) + 4) % 4
+ ? deltaRotation(mCurrentRotation, mNextRotation)
: Surface.ROTATION_0;
+ if (rotationDelta != Surface.ROTATION_0) {
+ sourceHintRect = computeRotatedBounds(rotationDelta, direction, destinationBounds,
+ sourceHintRect);
+ }
Rect baseBounds = direction == TRANSITION_DIRECTION_SNAP_AFTER_RESIZE
? mPipBoundsState.getBounds() : currentBounds;
final PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController
@@ -1107,9 +1228,35 @@
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(durationMs)
.start();
+ if (rotationDelta != Surface.ROTATION_0 && direction == TRANSITION_DIRECTION_TO_PIP) {
+ // The destination bounds are used for the end rect of animation and the final bounds
+ // after animation finishes. So after the animation is started, the destination bounds
+ // can be updated to new rotation (computeRotatedBounds has changed the DisplayLayout
+ // without affecting the animation.
+ animator.setDestinationBounds(mPipBoundsAlgorithm.getEntryDestinationBounds());
+ }
return animator;
}
+ /** Computes destination bounds in old rotation and returns source hint rect if available. */
+ private @Nullable Rect computeRotatedBounds(int rotationDelta, int direction,
+ Rect outDestinationBounds, Rect sourceHintRect) {
+ if (direction == TRANSITION_DIRECTION_TO_PIP) {
+ mPipBoundsState.getDisplayLayout().rotateTo(mContext.getResources(), mNextRotation);
+ final Rect displayBounds = mPipBoundsState.getDisplayBounds();
+ outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
+ // Transform the destination bounds to current display coordinates.
+ rotateBounds(outDestinationBounds, displayBounds, mNextRotation, mCurrentRotation);
+ } else if (direction == TRANSITION_DIRECTION_LEAVE_PIP) {
+ final Rect rotatedDestinationBounds = new Rect(outDestinationBounds);
+ rotateBounds(rotatedDestinationBounds, mPipBoundsState.getDisplayBounds(),
+ rotationDelta);
+ return PipBoundsAlgorithm.getValidSourceHintRect(mPictureInPictureParams,
+ rotatedDestinationBounds);
+ }
+ return sourceHintRect;
+ }
+
/**
* Sync with {@link LegacySplitScreenController} on destination bounds if PiP is going to split
* screen.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index f505e60..b881fea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -114,13 +114,17 @@
*/
private final DisplayChangeController.OnDisplayChangingListener mRotationController = (
int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
- if (!mPipTaskOrganizer.isInPip()
- || mPipBoundsState.getDisplayLayout().rotation() == toRotation
- || mPipTaskOrganizer.isDeferringEnterPipAnimation()
- || mPipTaskOrganizer.isEntryScheduled()) {
- // Skip if the same rotation has been set or we aren't in PIP or haven't actually
- // entered PIP yet. We still need to update the display layout in the bounds handler
- // in this case.
+ if (mPipBoundsState.getDisplayLayout().rotation() == toRotation) {
+ // The same rotation may have been set by auto PiP-able or fixed rotation. So notify
+ // the change with fromRotation=false to apply the rotated destination bounds from
+ // PipTaskOrganizer#onMovementBoundsChanged.
+ updateMovementBounds(null, false /* fromRotation */,
+ false /* fromImeAdjustment */, false /* fromShelfAdjustment */, t);
+ return;
+ }
+ if (!mPipTaskOrganizer.isInPip() || mPipTaskOrganizer.isEntryScheduled()) {
+ // Update display layout and bounds handler if we aren't in PIP or haven't actually
+ // entered PIP yet.
onDisplayRotationChangedNotInPip(mContext, toRotation);
// do not forget to update the movement bounds as well.
updateMovementBounds(mPipBoundsState.getNormalBounds(), true /* fromRotation */,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index c91a92a..efaa269 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -337,6 +337,7 @@
final WindowContainerTransaction wct = new WindowContainerTransaction();
// Make the stages adjacent to each other so they occlude what's behind them.
wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
+ wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
mTaskOrganizer.applyTransaction(wct);
}
}
@@ -346,6 +347,7 @@
final WindowContainerTransaction wct = new WindowContainerTransaction();
// Deactivate the main stage if it no longer has a root task.
mMainStage.deactivate(wct);
+ wct.clearLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
mTaskOrganizer.applyTransaction(wct);
}
}
@@ -449,6 +451,7 @@
final WindowContainerTransaction wct = new WindowContainerTransaction();
// Make sure the main stage is active.
mMainStage.activate(getMainStageBounds(), wct);
+ mSideStage.setBounds(getSideStageBounds(), wct);
mTaskOrganizer.applyTransaction(wct);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index ccf062e..1d3a60b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -18,7 +18,6 @@
import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static android.os.UserHandle.getUserHandleForUid;
import android.annotation.ColorInt;
import android.annotation.NonNull;
@@ -68,11 +67,12 @@
// For example, an icon with the foreground 108*108 opaque pixels and it's background
// also 108*108 pixels, then do not enlarge this icon if only need to show foreground icon.
private static final float ENLARGE_FOREGROUND_ICON_THRESHOLD = (72f * 72f) / (108f * 108f);
+ private static final float NO_BACKGROUND_SCALE = 1.3f;
private final Context mContext;
private final IconProvider mIconProvider;
- private final int mMaxAnimatableIconDuration;
private int mIconSize;
+ private int mDefaultIconSize;
private int mBrandingImageWidth;
private int mBrandingImageHeight;
private final int mAppRevealDuration;
@@ -84,11 +84,10 @@
private final SplashScreenWindowAttrs mTmpAttrs = new SplashScreenWindowAttrs();
private final Handler mSplashscreenWorkerHandler;
- SplashscreenContentDrawer(Context context, int maxAnimatableIconDuration,
- int iconExitAnimDuration, int appRevealAnimDuration, TransactionPool pool) {
+ SplashscreenContentDrawer(Context context, int iconExitAnimDuration, int appRevealAnimDuration,
+ TransactionPool pool) {
mContext = context;
mIconProvider = new IconProvider(context);
- mMaxAnimatableIconDuration = maxAnimatableIconDuration;
mAppRevealDuration = appRevealAnimDuration;
mIconExitDuration = iconExitAnimDuration;
mTransactionPool = pool;
@@ -122,11 +121,7 @@
context, splashScreenResId);
if (contentView == null) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "makeSplashScreenContentView");
- if (emptyView) {
- contentView = makeEmptySplashScreenContentView(context);
- } else {
- contentView = makeSplashScreenContentView(context, info);
- }
+ contentView = makeSplashScreenContentView(context, info, emptyView);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
} catch (RuntimeException e) {
@@ -141,6 +136,8 @@
private void updateDensity() {
mIconSize = mContext.getResources().getDimensionPixelSize(
com.android.wm.shell.R.dimen.starting_surface_icon_size);
+ mDefaultIconSize = mContext.getResources().getDimensionPixelSize(
+ com.android.wm.shell.R.dimen.default_icon_size);
mBrandingImageWidth = mContext.getResources().getDimensionPixelSize(
com.android.wm.shell.R.dimen.starting_surface_brand_image_width);
mBrandingImageHeight = mContext.getResources().getDimensionPixelSize(
@@ -195,46 +192,20 @@
}
}
- private SplashScreenView makeEmptySplashScreenContentView(Context context) {
- getWindowAttrs(context, mTmpAttrs);
- final StartingWindowViewBuilder builder = new StartingWindowViewBuilder();
- final int themeBGColor = peekWindowBGColor(context);
- final SplashScreenView view = builder
- .setContext(context)
- .setWindowBGColor(themeBGColor)
- .build();
- view.setNotCopyable();
- return view;
- }
-
- private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai) {
+ private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai,
+ boolean emptyView) {
updateDensity();
getWindowAttrs(context, mTmpAttrs);
final StartingWindowViewBuilder builder = new StartingWindowViewBuilder();
- final int animationDuration;
- Drawable iconDrawable;
- if (mTmpAttrs.mReplaceIcon != null) {
- iconDrawable = mTmpAttrs.mReplaceIcon;
- animationDuration = Math.max(0,
- Math.min(mTmpAttrs.mAnimationDuration, mMaxAnimatableIconDuration));
- } else {
- iconDrawable = mIconProvider.getIconForUI(
- ai, getUserHandleForUid(ai.applicationInfo.uid));
- if (iconDrawable == null) {
- iconDrawable = context.getPackageManager().getDefaultActivityIcon();
- }
- animationDuration = 0;
- }
final int themeBGColor = peekWindowBGColor(context);
// TODO (b/173975965) Tracking the performance on improved splash screen.
return builder
.setContext(context)
.setWindowBGColor(themeBGColor)
- .setIconDrawable(iconDrawable)
- .setIconAnimationDuration(animationDuration)
- .setBrandingDrawable(mTmpAttrs.mBrandingImage)
- .setIconBackground(mTmpAttrs.mIconBgColor).build();
+ .makeEmptyView(emptyView)
+ .setActivityInfo(ai)
+ .build();
}
private static void getWindowAttrs(Context context, SplashScreenWindowAttrs attrs) {
@@ -270,11 +241,9 @@
}
private class StartingWindowViewBuilder {
- private Drawable mIconDrawable;
- private int mIconAnimationDuration;
+ private ActivityInfo mActivityInfo;
private Context mContext;
- private Drawable mBrandingDrawable;
- private @ColorInt int mIconBackground;
+ private boolean mEmptyView;
// result
private boolean mBuildComplete = false;
@@ -289,26 +258,14 @@
return this;
}
- StartingWindowViewBuilder setIconDrawable(Drawable iconDrawable) {
- mIconDrawable = iconDrawable;
+ StartingWindowViewBuilder makeEmptyView(boolean empty) {
+ mEmptyView = empty;
mBuildComplete = false;
return this;
}
- StartingWindowViewBuilder setIconAnimationDuration(int iconAnimationDuration) {
- mIconAnimationDuration = iconAnimationDuration;
- mBuildComplete = false;
- return this;
- }
-
- StartingWindowViewBuilder setBrandingDrawable(Drawable branding) {
- mBrandingDrawable = branding;
- mBuildComplete = false;
- return this;
- }
-
- StartingWindowViewBuilder setIconBackground(int color) {
- mIconBackground = color;
+ StartingWindowViewBuilder setActivityInfo(ActivityInfo ai) {
+ mActivityInfo = ai;
mBuildComplete = false;
return this;
}
@@ -323,40 +280,66 @@
if (mBuildComplete) {
return mCachedResult;
}
- if (mContext == null) {
+ if (mContext == null || mActivityInfo == null) {
Slog.e(TAG, "Unable to create StartingWindowView, lack of materials!");
return null;
}
- if (!processAdaptiveIcon() && mIconDrawable != null) {
- if (DEBUG) {
- Slog.d(TAG, "The icon is not an AdaptiveIconDrawable");
+ Drawable iconDrawable;
+ final int animationDuration;
+ final int iconSize;
+ if (mEmptyView) {
+ // empty splash screen case
+ animationDuration = 0;
+ iconSize = 0;
+ } else if (mTmpAttrs.mReplaceIcon != null) {
+ // replaced icon, don't process
+ iconDrawable = mTmpAttrs.mReplaceIcon;
+ animationDuration = mTmpAttrs.mAnimationDuration;
+ createIconDrawable(iconDrawable, mIconSize);
+ iconSize = mIconSize;
+ } else {
+ final float iconScale = (float) mIconSize / (float) mDefaultIconSize;
+ iconDrawable = mIconProvider.getIcon(mActivityInfo);
+ if (iconDrawable == null) {
+ iconDrawable = mContext.getPackageManager().getDefaultActivityIcon();
}
- createIconDrawable(mIconDrawable, mIconSize);
+ if (!processAdaptiveIcon(iconDrawable, iconScale)) {
+ if (DEBUG) {
+ Slog.d(TAG, "The icon is not an AdaptiveIconDrawable");
+ }
+ // TODO process legacy icon(bitmap)
+ final Drawable tempIcon = loadIconByDensity(iconDrawable, iconScale);
+ createIconDrawable(tempIcon, mIconSize);
+ }
+ animationDuration = 0;
+ iconSize = (int) (0.5 + mIconSize * mScale);
}
- final int iconSize = mFinalIconDrawable != null ? (int) (mIconSize * mScale) : 0;
- mCachedResult = fillViewWithIcon(mContext, iconSize, mFinalIconDrawable);
+
+ mCachedResult = fillViewWithIcon(iconSize, mFinalIconDrawable, animationDuration);
mBuildComplete = true;
return mCachedResult;
}
private void createIconDrawable(Drawable iconDrawable, int iconSize) {
mFinalIconDrawable = SplashscreenIconDrawableFactory.makeIconDrawable(
- mIconBackground != Color.TRANSPARENT ? mIconBackground : mThemeColor,
+ mTmpAttrs.mIconBgColor != Color.TRANSPARENT
+ ? mTmpAttrs.mIconBgColor : mThemeColor,
iconDrawable, iconSize, mSplashscreenWorkerHandler);
}
- private boolean processAdaptiveIcon() {
- if (!(mIconDrawable instanceof AdaptiveIconDrawable)) {
+ private boolean processAdaptiveIcon(Drawable iconDrawable, float iconScale) {
+ if (!(iconDrawable instanceof AdaptiveIconDrawable)) {
return false;
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "processAdaptiveIcon");
- final AdaptiveIconDrawable adaptiveIconDrawable = (AdaptiveIconDrawable) mIconDrawable;
+ final AdaptiveIconDrawable adaptiveIconDrawable =
+ (AdaptiveIconDrawable) iconDrawable;
final DrawableColorTester backIconTester =
new DrawableColorTester(adaptiveIconDrawable.getBackground());
- final Drawable iconForeground = adaptiveIconDrawable.getForeground();
+ Drawable iconForeground = adaptiveIconDrawable.getForeground();
final DrawableColorTester foreIconTester =
new DrawableColorTester(iconForeground, true /* filterTransparent */);
@@ -382,7 +365,9 @@
// B. The background of the adaptive icon is similar to the theme color, or
// C. The background of the adaptive icon is grayscale, and the foreground of the
// adaptive icon forms a certain contrast with the theme color.
- if (!backComplex && (isRgbSimilarInHsv(mThemeColor, backMainColor)
+ // D. Didn't specify icon background color.
+ if (!backComplex && mTmpAttrs.mIconBgColor == Color.TRANSPARENT
+ && (isRgbSimilarInHsv(mThemeColor, backMainColor)
|| (backIconTester.isGrayscale()
&& !isRgbSimilarInHsv(mThemeColor, foreMainColor)))) {
if (DEBUG) {
@@ -390,8 +375,13 @@
}
// Reference AdaptiveIcon description, outer is 108 and inner is 72, so we
// should enlarge the size 108/72 if we only draw adaptiveIcon's foreground.
- if (foreIconTester.nonTransparentRatio() < ENLARGE_FOREGROUND_ICON_THRESHOLD) {
- mScale = 1.5f;
+ final float noBgScale =
+ foreIconTester.nonTransparentRatio() < ENLARGE_FOREGROUND_ICON_THRESHOLD
+ ? NO_BACKGROUND_SCALE : 1f;
+ final Drawable tempIcon = loadIconByDensity(iconDrawable, iconScale * noBgScale);
+ if (tempIcon instanceof AdaptiveIconDrawable) {
+ mScale = noBgScale;
+ iconForeground = ((AdaptiveIconDrawable) tempIcon).getForeground();
}
// Using AdaptiveIconDrawable here can help keep the shape consistent with the
// current settings.
@@ -401,30 +391,44 @@
if (DEBUG) {
Slog.d(TAG, "makeSplashScreenContentView: draw whole icon");
}
- createIconDrawable(adaptiveIconDrawable, mIconSize);
+ final Drawable tempIcon = loadIconByDensity(iconDrawable, iconScale);
+ createIconDrawable(tempIcon, mIconSize);
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return true;
}
- private SplashScreenView fillViewWithIcon(Context context,
- int iconSize, Drawable iconDrawable) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon");
- final SplashScreenView.Builder builder = new SplashScreenView.Builder(context);
- builder.setIconSize(iconSize).setBackgroundColor(mThemeColor)
- .setIconBackground(mIconBackground);
- if (iconDrawable != null) {
- builder.setCenterViewDrawable(iconDrawable);
+ private Drawable loadIconByDensity(Drawable baseDrawable, float scale) {
+ if (scale == 1 && baseDrawable != null) {
+ return baseDrawable;
}
- builder.setAnimationDurationMillis(mIconAnimationDuration);
- if (mBrandingDrawable != null) {
- builder.setBrandingDrawable(mBrandingDrawable, mBrandingImageWidth,
+ final int densityDpi = mContext.getResources().getDisplayMetrics().densityDpi;
+ final int updateDpi = (int) (0.5f + scale * densityDpi);
+ return mIconProvider.getIcon(mActivityInfo, updateDpi);
+ }
+
+ private SplashScreenView fillViewWithIcon(int iconSize, Drawable iconDrawable,
+ int animationDuration) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon");
+ final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext);
+ builder.setBackgroundColor(mThemeColor);
+ if (iconDrawable != null) {
+ builder.setIconSize(iconSize)
+ .setIconBackground(mTmpAttrs.mIconBgColor)
+ .setCenterViewDrawable(iconDrawable)
+ .setAnimationDurationMillis(animationDuration);
+ }
+ if (mTmpAttrs.mBrandingImage != null) {
+ builder.setBrandingDrawable(mTmpAttrs.mBrandingImage, mBrandingImageWidth,
mBrandingImageHeight);
}
final SplashScreenView splashScreenView = builder.build();
if (DEBUG) {
Slog.d(TAG, "fillViewWithIcon surfaceWindowView " + splashScreenView);
}
+ if (mEmptyView) {
+ splashScreenView.setNotCopyable();
+ }
splashScreenView.makeSystemUIColorsTransparent();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return splashScreenView;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index 85845d0..6cbba9f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -59,6 +59,7 @@
return new ImmobileIconDrawable((AdaptiveIconDrawable) foregroundDrawable, iconSize,
splashscreenWorkerHandler);
} else {
+ // TODO for legacy icon don't use adaptive icon drawable to wrapper it
return new ImmobileIconDrawable(new AdaptiveIconDrawable(
new ColorDrawable(backgroundColor), foregroundDrawable), iconSize,
splashscreenWorkerHandler);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index e4b2869..6d3eeae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -114,14 +114,12 @@
mContext = context;
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mSplashScreenExecutor = splashScreenExecutor;
- final int maxAnimatableIconDuration = context.getResources().getInteger(
- com.android.wm.shell.R.integer.max_starting_window_intro_icon_anim_duration);
final int iconExitAnimDuration = context.getResources().getInteger(
com.android.wm.shell.R.integer.starting_window_icon_exit_anim_duration);
final int appRevealAnimDuration = context.getResources().getInteger(
com.android.wm.shell.R.integer.starting_window_app_reveal_anim_duration);
- mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext,
- maxAnimatableIconDuration, iconExitAnimDuration, appRevealAnimDuration, pool);
+ mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, iconExitAnimDuration,
+ appRevealAnimDuration, pool);
mSplashScreenExecutor.execute(() -> mChoreographer = Choreographer.getInstance());
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index e336287..cb7afc7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -15,18 +15,10 @@
*/
package com.android.wm.shell.startingsurface;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN;
-import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_NONE;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_SAME_PACKAGE;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
@@ -68,27 +60,24 @@
*/
public class StartingWindowController implements RemoteCallable<StartingWindowController> {
private static final String TAG = StartingWindowController.class.getSimpleName();
+
// TODO b/183150443 Keep this flag open for a while, several things might need to adjust.
- static final boolean DEBUG_SPLASH_SCREEN = true;
- static final boolean DEBUG_TASK_SNAPSHOT = false;
+ public static final boolean DEBUG_SPLASH_SCREEN = true;
+ public static final boolean DEBUG_TASK_SNAPSHOT = false;
private final StartingSurfaceDrawer mStartingSurfaceDrawer;
- private final StartingTypeChecker mStartingTypeChecker = new StartingTypeChecker();
+ private final StartingWindowTypeAlgorithm mStartingWindowTypeAlgorithm;
private BiConsumer<Integer, Integer> mTaskLaunchingCallback;
private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
private final Context mContext;
private final ShellExecutor mSplashScreenExecutor;
- // For Car Launcher
- public StartingWindowController(Context context, ShellExecutor splashScreenExecutor) {
- this(context, splashScreenExecutor, new TransactionPool());
- }
-
public StartingWindowController(Context context, ShellExecutor splashScreenExecutor,
- TransactionPool pool) {
+ StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, TransactionPool pool) {
mContext = context;
mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, pool);
+ mStartingWindowTypeAlgorithm = startingWindowTypeAlgorithm;
mSplashScreenExecutor = splashScreenExecutor;
}
@@ -109,90 +98,6 @@
return mSplashScreenExecutor;
}
- private static class StartingTypeChecker {
-
- private @StartingWindowInfo.StartingWindowType int
- estimateStartingWindowType(StartingWindowInfo windowInfo) {
- final int parameter = windowInfo.startingWindowTypeParameter;
- final boolean newTask = (parameter & TYPE_PARAMETER_NEW_TASK) != 0;
- final boolean taskSwitch = (parameter & TYPE_PARAMETER_TASK_SWITCH) != 0;
- final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0;
- final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0;
- final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0;
- final boolean samePackage = (parameter & TYPE_PARAMETER_SAME_PACKAGE) != 0;
- return estimateStartingWindowType(windowInfo, newTask, taskSwitch,
- processRunning, allowTaskSnapshot, activityCreated, samePackage);
- }
-
- // reference from ActivityRecord#getStartingWindowType
- private int estimateStartingWindowType(StartingWindowInfo windowInfo,
- boolean newTask, boolean taskSwitch, boolean processRunning,
- boolean allowTaskSnapshot, boolean activityCreated, boolean samePackage) {
- if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
- Slog.d(TAG, "preferredStartingWindowType newTask " + newTask
- + " taskSwitch " + taskSwitch
- + " processRunning " + processRunning
- + " allowTaskSnapshot " + allowTaskSnapshot
- + " activityCreated " + activityCreated
- + " samePackage " + samePackage);
- }
- if (windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
- if (!processRunning) {
- return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
- }
- if (newTask) {
- if (samePackage) {
- return STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN;
- } else {
- return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
- }
- }
- if (taskSwitch && !activityCreated) {
- return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
- }
- }
- if (taskSwitch && allowTaskSnapshot) {
- final TaskSnapshot snapshot = windowInfo.mTaskSnapshot;
- if (isSnapshotCompatible(windowInfo, snapshot)) {
- return STARTING_WINDOW_TYPE_SNAPSHOT;
- }
- if (windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
- return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
- }
- }
- return STARTING_WINDOW_TYPE_NONE;
- }
-
- /**
- * Returns {@code true} if the task snapshot is compatible with this activity (at least the
- * rotation must be the same).
- */
- private boolean isSnapshotCompatible(StartingWindowInfo windowInfo, TaskSnapshot snapshot) {
- if (snapshot == null) {
- if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
- Slog.d(TAG, "isSnapshotCompatible no snapshot " + windowInfo.taskInfo.taskId);
- }
- return false;
- }
- if (!snapshot.getTopActivityComponent().equals(windowInfo.taskInfo.topActivity)) {
- if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
- Slog.d(TAG, "isSnapshotCompatible obsoleted snapshot "
- + windowInfo.taskInfo.topActivity);
- }
- return false;
- }
-
- final int taskRotation = windowInfo.taskInfo.configuration
- .windowConfiguration.getRotation();
- final int snapshotRotation = snapshot.getRotation();
- if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
- Slog.d(TAG, "isSnapshotCompatible rotation " + taskRotation
- + " snapshot " + snapshotRotation);
- }
- return taskRotation == snapshotRotation;
- }
- }
-
/*
* Registers the starting window listener.
*
@@ -212,7 +117,8 @@
public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
mSplashScreenExecutor.execute(() -> {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addStartingWindow");
- final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(
+
+ final int suggestionType = mStartingWindowTypeAlgorithm.getSuggestedWindowType(
windowInfo);
final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
if (mTaskLaunchingCallback != null && shouldSendToListener(suggestionType)) {
@@ -228,8 +134,10 @@
final TaskSnapshot snapshot = windowInfo.mTaskSnapshot;
mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken,
snapshot);
+ } else /* suggestionType == STARTING_WINDOW_TYPE_NONE */ {
+ // Don't add a staring window.
}
- // If prefer don't show, then don't show!
+
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowTypeAlgorithm.java
new file mode 100644
index 0000000..de221ed
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowTypeAlgorithm.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.startingsurface;
+
+import android.window.StartingWindowInfo;
+
+/**
+ * Used by {@link StartingWindowController} for determining the type of a new starting window.
+ */
+public interface StartingWindowTypeAlgorithm {
+ /**
+ * @return suggested type for the given window.
+ */
+ @StartingWindowInfo.StartingWindowType
+ int getSuggestedWindowType(StartingWindowInfo windowInfo);
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
new file mode 100644
index 0000000..9948e7d
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.startingsurface.phone;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_NONE;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_SAME_PACKAGE;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
+
+import static com.android.wm.shell.startingsurface.StartingWindowController.DEBUG_SPLASH_SCREEN;
+import static com.android.wm.shell.startingsurface.StartingWindowController.DEBUG_TASK_SNAPSHOT;
+
+import android.util.Slog;
+import android.window.StartingWindowInfo;
+import android.window.TaskSnapshot;
+
+import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm;
+
+/**
+ * Algorithm for determining the type of a new starting window on handheld devices.
+ * At the moment also used on Android Auto.
+ */
+public class PhoneStartingWindowTypeAlgorithm implements StartingWindowTypeAlgorithm {
+ private static final String TAG = PhoneStartingWindowTypeAlgorithm.class.getSimpleName();
+
+ @Override
+ public int getSuggestedWindowType(StartingWindowInfo windowInfo) {
+ final int parameter = windowInfo.startingWindowTypeParameter;
+ final boolean newTask = (parameter & TYPE_PARAMETER_NEW_TASK) != 0;
+ final boolean taskSwitch = (parameter & TYPE_PARAMETER_TASK_SWITCH) != 0;
+ final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0;
+ final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0;
+ final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0;
+ final boolean samePackage = (parameter & TYPE_PARAMETER_SAME_PACKAGE) != 0;
+ final boolean topIsHome = windowInfo.taskInfo.topActivityType == ACTIVITY_TYPE_HOME;
+
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "preferredStartingWindowType newTask " + newTask
+ + " taskSwitch " + taskSwitch
+ + " processRunning " + processRunning
+ + " allowTaskSnapshot " + allowTaskSnapshot
+ + " activityCreated " + activityCreated
+ + " samePackage " + samePackage
+ + " topIsHome " + topIsHome);
+ }
+ if (!topIsHome) {
+ if (!processRunning) {
+ return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ }
+ if (newTask) {
+ if (samePackage) {
+ return STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN;
+ } else {
+ return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ }
+ }
+ if (taskSwitch && !activityCreated) {
+ return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ }
+ }
+ if (taskSwitch && allowTaskSnapshot) {
+ if (isSnapshotCompatible(windowInfo)) {
+ return STARTING_WINDOW_TYPE_SNAPSHOT;
+ }
+ if (!topIsHome) {
+ return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ }
+ }
+ return STARTING_WINDOW_TYPE_NONE;
+ }
+
+
+ /**
+ * Returns {@code true} if the task snapshot is compatible with this activity (at least the
+ * rotation must be the same).
+ */
+ private boolean isSnapshotCompatible(StartingWindowInfo windowInfo) {
+ final TaskSnapshot snapshot = windowInfo.mTaskSnapshot;
+ if (snapshot == null) {
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "isSnapshotCompatible no snapshot " + windowInfo.taskInfo.taskId);
+ }
+ return false;
+ }
+ if (!snapshot.getTopActivityComponent().equals(windowInfo.taskInfo.topActivity)) {
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "isSnapshotCompatible obsoleted snapshot "
+ + windowInfo.taskInfo.topActivity);
+ }
+ return false;
+ }
+
+ final int taskRotation = windowInfo.taskInfo.configuration
+ .windowConfiguration.getRotation();
+ final int snapshotRotation = snapshot.getRotation();
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "isSnapshotCompatible rotation " + taskRotation
+ + " snapshot " + snapshotRotation);
+ }
+ return taskRotation == snapshotRotation;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/tv/TvStartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/tv/TvStartingWindowTypeAlgorithm.java
new file mode 100644
index 0000000..6e7dec5
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/tv/TvStartingWindowTypeAlgorithm.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.startingsurface.tv;
+
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN;
+
+import android.window.StartingWindowInfo;
+
+import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm;
+
+/**
+ * Algorithm for determining the type of a new starting window on Android TV.
+ * For now we always show empty splash screens on Android TV.
+ */
+public class TvStartingWindowTypeAlgorithm implements StartingWindowTypeAlgorithm {
+ @Override
+ public int getSuggestedWindowType(StartingWindowInfo windowInfo) {
+ // For now we want to always show empty splash screens on TV.
+ return STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
index 6bc9a5c..58e9204 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
@@ -25,7 +25,6 @@
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.canSplitScreen
-import com.android.server.wm.flicker.helpers.openQuickstep
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -64,7 +63,6 @@
}
}
transitions {
- device.openQuickstep(wmHelper)
if (device.canSplitScreen(wmHelper)) {
Assert.fail("Non-resizeable app should not enter split screen")
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
index 63b9413..882d382 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
@@ -18,6 +18,7 @@
import static android.util.RotationUtils.rotateBounds;
import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
@@ -133,17 +134,30 @@
@Test
public void pipTransitionAnimator_rotatedEndValue() {
+ final DummySurfaceControlTx tx = new DummySurfaceControlTx();
final Rect startBounds = new Rect(200, 700, 400, 800);
final Rect endBounds = new Rect(0, 0, 500, 1000);
- final PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController
+ // Fullscreen to PiP.
+ PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController
.getAnimator(mTaskInfo, mLeash, null, startBounds, endBounds, null,
- TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_90);
+ TRANSITION_DIRECTION_LEAVE_PIP, 0, ROTATION_90);
// Apply fraction 1 to compute the end value.
- animator.applySurfaceControlTransaction(mLeash, new DummySurfaceControlTx(), 1);
+ animator.applySurfaceControlTransaction(mLeash, tx, 1);
final Rect rotatedEndBounds = new Rect(endBounds);
rotateBounds(rotatedEndBounds, endBounds, ROTATION_90);
assertEquals("Expect 90 degree rotated bounds", rotatedEndBounds, animator.mCurrentValue);
+
+ // PiP to fullscreen.
+ startBounds.set(0, 0, 1000, 500);
+ endBounds.set(200, 100, 400, 500);
+ animator = mPipAnimationController.getAnimator(mTaskInfo, mLeash, startBounds, startBounds,
+ endBounds, null, TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_270);
+ animator.applySurfaceControlTransaction(mLeash, tx, 1);
+ rotatedEndBounds.set(endBounds);
+ rotateBounds(rotatedEndBounds, startBounds, ROTATION_270);
+
+ assertEquals("Expect 270 degree rotated bounds", rotatedEndBounds, animator.mCurrentValue);
}
@Test
diff --git a/libs/hwui/effects/StretchEffect.cpp b/libs/hwui/effects/StretchEffect.cpp
index c2642d3..6eb6e1e 100644
--- a/libs/hwui/effects/StretchEffect.cpp
+++ b/libs/hwui/effects/StretchEffect.cpp
@@ -237,7 +237,7 @@
}
sk_sp<SkRuntimeEffect> StretchEffect::getStretchEffect() {
- const static SkRuntimeEffect::Result instance = SkRuntimeEffect::Make(stretchShader);
+ const static SkRuntimeEffect::Result instance = SkRuntimeEffect::MakeForShader(stretchShader);
return instance.effect;
}
diff --git a/libs/hwui/hwui/AnimatedImageThread.cpp b/libs/hwui/hwui/AnimatedImageThread.cpp
index c899003..3d5841d 100644
--- a/libs/hwui/hwui/AnimatedImageThread.cpp
+++ b/libs/hwui/hwui/AnimatedImageThread.cpp
@@ -22,13 +22,16 @@
namespace uirenderer {
AnimatedImageThread& AnimatedImageThread::getInstance() {
- static AnimatedImageThread* sInstance = new AnimatedImageThread();
- return *sInstance;
+ [[clang::no_destroy]] static sp<AnimatedImageThread> sInstance = []() {
+ sp<AnimatedImageThread> thread = sp<AnimatedImageThread>::make();
+ thread->start("AnimatedImageThread");
+ return thread;
+ }();
+ return *sInstance.get();
}
AnimatedImageThread::AnimatedImageThread() {
setpriority(PRIO_PROCESS, 0, PRIORITY_NORMAL + PRIORITY_MORE_FAVORABLE);
- start("AnimatedImageThread");
}
std::future<AnimatedImageDrawable::Snapshot> AnimatedImageThread::decodeNextFrame(
diff --git a/libs/hwui/hwui/AnimatedImageThread.h b/libs/hwui/hwui/AnimatedImageThread.h
index 9e35374..fac80e5 100644
--- a/libs/hwui/hwui/AnimatedImageThread.h
+++ b/libs/hwui/hwui/AnimatedImageThread.h
@@ -37,6 +37,7 @@
std::future<AnimatedImageDrawable::Snapshot> reset(const sk_sp<AnimatedImageDrawable>&);
private:
+ friend sp<AnimatedImageThread>;
AnimatedImageThread();
};
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 2e4d7f62..9018443 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -239,7 +239,8 @@
static jlong RuntimeShader_createShaderBuilder(JNIEnv* env, jobject, jstring sksl) {
ScopedUtfChars strSksl(env, sksl);
- auto result = SkRuntimeEffect::Make(SkString(strSksl.c_str()), SkRuntimeEffect::Options{});
+ auto result = SkRuntimeEffect::MakeForShader(SkString(strSksl.c_str()),
+ SkRuntimeEffect::Options{});
if (result.effect.get() == nullptr) {
doThrowIAE(env, result.errorText.c_str());
return 0;
diff --git a/libs/incident/Android.bp b/libs/incident/Android.bp
index f322bff..547d7192 100644
--- a/libs/incident/Android.bp
+++ b/libs/incident/Android.bp
@@ -104,7 +104,7 @@
name: "libincident_test",
test_config: "AndroidTest.xml",
defaults: ["libincidentpriv_defaults"],
- test_suites: ["device-tests", "mts-statsd"],
+ test_suites: ["device-tests"],
compile_multilib: "both",
multilib: {
lib64: {
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index 307fb87..51586d7 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -45,6 +45,10 @@
* empty list if there no backend service in the platform. Use the
* isPresent() method to determine whether a Geocoder implementation
* exists.
+ *
+ * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
+ * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful or
+ * correct. Do not use this API for any safety-critical or regulatory compliance purpose.
*/
public final class Geocoder {
@@ -95,15 +99,15 @@
}
/**
- * Returns an array of Addresses that are known to describe the
- * area immediately surrounding the given latitude and longitude.
- * The returned addresses will be localized for the locale
- * provided to this class's constructor.
+ * Returns an array of Addresses that attempt to describe the area immediately surrounding the
+ * given latitude and longitude. The returned addresses should be localized for the locale
+ * provided to this class's constructor. Results may be obtained by means of a network lookup
+ * and this method may take some time to return, and so should not be called on the main thread.
*
- * <p> The returned values may be obtained by means of a network lookup.
- * The results are a best guess and are not guaranteed to be meaningful or
- * correct. It may be useful to call this method from a thread separate from your
- * primary UI thread.
+ * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
+ * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
+ * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
+ * purposes.
*
* @param latitude the latitude a point for the search
* @param longitude the longitude a point for the search
@@ -134,17 +138,17 @@
}
/**
- * Returns an array of Addresses that are known to describe the
- * named location, which may be a place name such as "Dalvik,
- * Iceland", an address such as "1600 Amphitheatre Parkway,
- * Mountain View, CA", an airport code such as "SFO", etc.. The
- * returned addresses will be localized for the locale provided to
- * this class's constructor.
+ * Returns an array of Addresses that attempt to describe the named location, which may be a
+ * place name such as "Dalvik, Iceland", an address such as "1600 Amphitheatre Parkway, Mountain
+ * View, CA", an airport code such as "SFO", and so forth. The returned addresses should be
+ * localized for the locale provided to this class's constructor. Results may be obtained by
+ * means of a network lookup and this method may take some time to return, and so should not be
+ * called on the main thread.
*
- * <p> The query will block and returned values will be obtained by means of a network lookup.
- * The results are a best guess and are not guaranteed to be meaningful or
- * correct. It may be useful to call this method from a thread separate from your
- * primary UI thread.
+ * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
+ * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
+ * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
+ * purposes.
*
* @param locationName a user-supplied description of a location
* @param maxResults max number of results to return. Smaller numbers (1 to 5) are recommended
@@ -161,21 +165,20 @@
}
/**
- * Returns an array of Addresses that are known to describe the
- * named location, which may be a place name such as "Dalvik,
- * Iceland", an address such as "1600 Amphitheatre Parkway,
- * Mountain View, CA", an airport code such as "SFO", etc.. The
- * returned addresses will be localized for the locale provided to
- * this class's constructor.
+ * Returns an array of Addresses that attempt to describe the named location, which may be a
+ * place name such as "Dalvik, Iceland", an address such as "1600 Amphitheatre Parkway, Mountain
+ * View, CA", an airport code such as "SFO", and so forth. The returned addresses should be
+ * localized for the locale provided to this class's constructor. Results may be obtained by
+ * means of a network lookup and this method may take some time to return, and so should not be
+ * called on the main thread.
*
- * <p> You may specify a bounding box for the search results by including
- * the Latitude and Longitude of the Lower Left point and Upper Right
- * point of the box.
+ * <p> You may specify a bounding box for the search results by including the latitude and
+ * longitude of the lower left point and upper right point of the box.
*
- * <p> The query will block and returned values will be obtained by means of a network lookup.
- * The results are a best guess and are not guaranteed to be meaningful or
- * correct. It may be useful to call this method from a thread separate from your
- * primary UI thread.
+ * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
+ * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
+ * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
+ * purposes.
*
* @param locationName a user-supplied description of a location
* @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are recommended
diff --git a/media/java/android/media/MediaServiceManager.java b/media/java/android/media/MediaServiceManager.java
index b899559..fd89c0c 100644
--- a/media/java/android/media/MediaServiceManager.java
+++ b/media/java/android/media/MediaServiceManager.java
@@ -45,12 +45,21 @@
*/
public static final class ServiceRegisterer {
private final String mServiceName;
+ private final boolean mLazyStart;
+
+ /**
+ * @hide
+ */
+ public ServiceRegisterer(String serviceName, boolean lazyStart) {
+ mServiceName = serviceName;
+ mLazyStart = lazyStart;
+ }
/**
* @hide
*/
public ServiceRegisterer(String serviceName) {
- mServiceName = serviceName;
+ this(serviceName, false /*lazyStart*/);
}
/**
@@ -61,6 +70,9 @@
*/
@Nullable
public IBinder get() {
+ if (mLazyStart) {
+ return ServiceManager.waitForService(mServiceName);
+ }
return ServiceManager.getService(mServiceName);
}
}
@@ -78,7 +90,7 @@
*/
@NonNull
public ServiceRegisterer getMediaTranscodingServiceRegisterer() {
- return new ServiceRegisterer(MEDIA_TRANSCODING_SERVICE);
+ return new ServiceRegisterer(MEDIA_TRANSCODING_SERVICE, true /*lazyStart*/);
}
/**
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 24c93ce..3ee2c18 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -127,7 +127,11 @@
cc_library_shared {
name: "libandroid_net",
defaults: ["libandroid_defaults"],
- llndk_stubs: "libandroid_net.llndk",
+ llndk: {
+ symbol_file: "libandroid_net.map.txt",
+ unversioned: true,
+ override_export_include_dirs: ["include"],
+ },
srcs: ["net.c"],
shared_libs: ["libnetd_client"],
@@ -135,13 +139,6 @@
include_dirs: ["bionic/libc/dns/include"],
}
-llndk_library {
- name: "libandroid_net.llndk",
- export_include_dirs: ["include"],
- symbol_file: "libandroid_net.map.txt",
- unversioned: true,
-}
-
// Aidl library for platform compat.
cc_library_shared {
name: "lib-platform-compat-native-api",
diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp
index 385e455..b0c8c61 100644
--- a/native/graphics/jni/imagedecoder.cpp
+++ b/native/graphics/jni/imagedecoder.cpp
@@ -442,6 +442,15 @@
return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
}
+ const auto colorType = imageDecoder->getOutputInfo().colorType();
+ switch (colorType) {
+ case kN32_SkColorType:
+ case kRGBA_F16_SkColorType:
+ break;
+ default:
+ return ANDROID_IMAGE_DECODER_INVALID_STATE;
+ }
+
if (imageDecoder->advanceFrame()) {
return ANDROID_IMAGE_DECODER_SUCCESS;
}
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index a8e2517..90580fa 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -10,7 +10,6 @@
method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshots();
method @Nullable public android.net.ProxyInfo getGlobalProxy();
method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange();
- method @NonNull public static String getPrivateDnsMode(@NonNull android.content.Context);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackForUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
@@ -20,7 +19,6 @@
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network);
method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean);
- method public static void setPrivateDnsMode(@NonNull android.content.Context, @NonNull String);
method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
@@ -40,9 +38,6 @@
field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10
field public static final int BLOCKED_REASON_NONE = 0; // 0x0
field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
- field public static final String PRIVATE_DNS_MODE_OFF = "off";
- field public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
- field public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
field public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; // 0x0
field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1
}
@@ -69,6 +64,7 @@
method @NonNull public static java.time.Duration getNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context);
method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context);
+ method public static int getPrivateDnsMode(@NonNull android.content.Context);
method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean);
method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String);
@@ -85,8 +81,9 @@
method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String);
method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int);
method public static void setNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull String);
+ method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull int);
method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String);
+ method public static void setPrivateDnsMode(@NonNull android.content.Context, int);
method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean);
method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
@@ -95,6 +92,9 @@
field public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; // 0x2
field public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; // 0x0
field public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; // 0x1
+ field public static final int PRIVATE_DNS_MODE_OFF = 1; // 0x1
+ field public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; // 0x2
+ field public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; // 0x3
}
public final class NetworkAgentConfig implements android.os.Parcelable {
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index 164b984..0c5eaa7 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -16,8 +16,6 @@
package android.net;
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE;
import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
import static android.net.NetworkRequest.Type.LISTEN;
import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST;
@@ -33,7 +31,6 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.StringDef;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -41,7 +38,6 @@
import android.app.admin.DevicePolicyManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityDiagnosticsManager.DataStallReport.DetectionMethod;
@@ -70,7 +66,6 @@
import android.provider.Settings;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Range;
@@ -821,38 +816,6 @@
public static final int NETID_UNSET = 0;
/**
- * Private DNS Mode values.
- *
- * The "private_dns_mode" global setting stores a String value which is
- * expected to be one of the following.
- */
-
- /**
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public static final String PRIVATE_DNS_MODE_OFF = "off";
- /**
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
- /**
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @StringDef(value = {
- PRIVATE_DNS_MODE_OFF,
- PRIVATE_DNS_MODE_OPPORTUNISTIC,
- PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
- })
- public @interface PrivateDnsMode {}
-
- /**
* Flag to indicate that an app is not subject to any restrictions that could result in its
* network access blocked.
*
@@ -5503,44 +5466,4 @@
public static Range<Integer> getIpSecNetIdRange() {
return new Range(TUN_INTF_NETID_START, TUN_INTF_NETID_START + TUN_INTF_NETID_RANGE - 1);
}
-
- /**
- * Get private DNS mode from settings.
- *
- * @param context The Context to query the private DNS mode from settings.
- * @return A string of private DNS mode as one of the PRIVATE_DNS_MODE_* constants.
- *
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- @NonNull
- @PrivateDnsMode
- public static String getPrivateDnsMode(@NonNull Context context) {
- final ContentResolver cr = context.getContentResolver();
- String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE);
- if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE);
- // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose
- // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode.
- if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_MODE_OPPORTUNISTIC;
- return mode;
- }
-
- /**
- * Set private DNS mode to settings.
- *
- * @param context The {@link Context} to set the private DNS mode.
- * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants.
- *
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public static void setPrivateDnsMode(@NonNull Context context,
- @NonNull @PrivateDnsMode String mode) {
- if (!(mode == PRIVATE_DNS_MODE_OFF
- || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
- || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
- throw new IllegalArgumentException("Invalid private dns mode");
- }
- Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, mode);
- }
}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
index 9a00055..31e1fb0 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
@@ -19,18 +19,15 @@
import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER;
import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE;
import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.content.ContentResolver;
import android.content.Context;
import android.net.ConnectivityManager.MultipathPreference;
-import android.net.ConnectivityManager.PrivateDnsMode;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Range;
@@ -341,6 +338,37 @@
public static final String MOBILE_DATA_PREFERRED_APPS = "mobile_data_preferred_apps";
/**
+ * One of the private DNS modes that indicates the private DNS mode is off.
+ */
+ public static final int PRIVATE_DNS_MODE_OFF = 1;
+
+ /**
+ * One of the private DNS modes that indicates the private DNS mode is automatic, which
+ * will try to use the current DNS as private DNS.
+ */
+ public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2;
+
+ /**
+ * One of the private DNS modes that indicates the private DNS mode is strict and the
+ * {@link #PRIVATE_DNS_SPECIFIER} is required, which will try to use the value of
+ * {@link #PRIVATE_DNS_SPECIFIER} as private DNS.
+ */
+ public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ PRIVATE_DNS_MODE_OFF,
+ PRIVATE_DNS_MODE_OPPORTUNISTIC,
+ PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
+ })
+ public @interface PrivateDnsMode {}
+
+ private static final String PRIVATE_DNS_MODE_OFF_STRING = "off";
+ private static final String PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING = "opportunistic";
+ private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING = "hostname";
+
+ /**
* Get mobile data activity timeout from {@link Settings}.
*
* @param context The {@link Context} to query the setting.
@@ -689,6 +717,65 @@
context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
}
+ private static String getPrivateDnsModeAsString(@PrivateDnsMode int mode) {
+ switch (mode) {
+ case PRIVATE_DNS_MODE_OFF:
+ return PRIVATE_DNS_MODE_OFF_STRING;
+ case PRIVATE_DNS_MODE_OPPORTUNISTIC:
+ return PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING;
+ case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
+ return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING;
+ default:
+ throw new IllegalArgumentException("Invalid private dns mode: " + mode);
+ }
+ }
+
+ private static int getPrivateDnsModeAsInt(String mode) {
+ switch (mode) {
+ case "off":
+ return PRIVATE_DNS_MODE_OFF;
+ case "hostname":
+ return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+ case "opportunistic":
+ return PRIVATE_DNS_MODE_OPPORTUNISTIC;
+ default:
+ throw new IllegalArgumentException("Invalid private dns mode: " + mode);
+ }
+ }
+
+ /**
+ * Get private DNS mode from settings.
+ *
+ * @param context The Context to query the private DNS mode from settings.
+ * @return A string of private DNS mode.
+ */
+ @PrivateDnsMode
+ public static int getPrivateDnsMode(@NonNull Context context) {
+ final ContentResolver cr = context.getContentResolver();
+ String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE);
+ if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE);
+ // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose
+ // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode.
+ if (TextUtils.isEmpty(mode)) return PRIVATE_DNS_MODE_OPPORTUNISTIC;
+ return getPrivateDnsModeAsInt(mode);
+ }
+
+ /**
+ * Set private DNS mode to settings.
+ *
+ * @param context The {@link Context} to set the private DNS mode.
+ * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants.
+ */
+ public static void setPrivateDnsMode(@NonNull Context context, @PrivateDnsMode int mode) {
+ if (!(mode == PRIVATE_DNS_MODE_OFF
+ || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
+ || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
+ throw new IllegalArgumentException("Invalid private dns mode: " + mode);
+ }
+ Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE,
+ getPrivateDnsModeAsString(mode));
+ }
+
/**
* Get specific private dns provider name from {@link Settings}.
*
@@ -731,13 +818,14 @@
* constants.
*/
public static void setPrivateDnsDefaultMode(@NonNull Context context,
- @NonNull @PrivateDnsMode String mode) {
+ @NonNull @PrivateDnsMode int mode) {
if (!(mode == PRIVATE_DNS_MODE_OFF
|| mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
|| mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
throw new IllegalArgumentException("Invalid private dns mode");
}
- Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE, mode);
+ Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE,
+ getPrivateDnsModeAsString(mode));
}
/**
diff --git a/packages/Connectivity/framework/src/android/net/ProxyInfo.java b/packages/Connectivity/framework/src/android/net/ProxyInfo.java
index 745e20f..0deda37 100644
--- a/packages/Connectivity/framework/src/android/net/ProxyInfo.java
+++ b/packages/Connectivity/framework/src/android/net/ProxyInfo.java
@@ -37,8 +37,9 @@
* Apache HTTP stack. So {@link URLConnection} and Apache's {@code HttpClient} will use
* them automatically.
*
- * Other HTTP stacks will need to obtain the proxy info from
- * {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}.
+ * Other HTTP stacks will need to obtain the proxy info by watching for the
+ * {@link Proxy#PROXY_CHANGE_ACTION} broadcast and calling methods such as
+ * {@link android.net.ConnectivityManager#getDefaultProxy}.
*/
public class ProxyInfo implements Parcelable {
diff --git a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
index 3f0a06c..50f69d1 100644
--- a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
+++ b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
@@ -64,7 +64,9 @@
style="@style/TextAppearance.EntityHeaderSummary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="2dp"/>
+ android:layout_marginTop="2dp"
+ android:singleLine="false"
+ android:textAlignment="center"/>
<TextView
android:id="@+id/entity_header_second_summary"
diff --git a/packages/SettingsLib/SearchWidget/res/values-es-rUS/strings.xml b/packages/SettingsLib/SearchWidget/res/values-es-rUS/strings.xml
index 9b735fe..d385101 100644
--- a/packages/SettingsLib/SearchWidget/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-es-rUS/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Buscar configuraciones"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Buscar configuración"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-kn/strings.xml b/packages/SettingsLib/SearchWidget/res/values-kn/strings.xml
index a492ec0..eccf6c7 100644
--- a/packages/SettingsLib/SearchWidget/res/values-kn/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-kn/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"ಹುಡುಕಾಟ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
+ <string name="search_menu" msgid="1914043873178389845">"ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಹುಡುಕಿ"</string>
</resources>
diff --git a/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java b/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
index 6560a18..ed447f8 100644
--- a/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
+++ b/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
@@ -25,6 +25,7 @@
import androidx.core.os.BuildCompat;
+import com.google.android.material.transition.platform.FadeThroughProvider;
import com.google.android.material.transition.platform.MaterialSharedAxis;
import com.google.android.material.transition.platform.SlideDistanceProvider;
@@ -35,6 +36,7 @@
private static final String TAG = "SettingsTransitionHelper";
private static final long DURATION = 450L;
+ private static final float FADE_THROUGH_THRESHOLD = 0.22F;
private static MaterialSharedAxis createSettingsSharedAxis(Context context, boolean forward) {
final MaterialSharedAxis transition = new MaterialSharedAxis(MaterialSharedAxis.X, forward);
@@ -48,12 +50,14 @@
forwardDistanceProvider.setSlideDistance(distance);
transition.setDuration(DURATION);
+ final FadeThroughProvider fadeThroughProvider =
+ (FadeThroughProvider) transition.getSecondaryAnimatorProvider();
+ fadeThroughProvider.setProgressThreshold(FADE_THROUGH_THRESHOLD);
+
final Interpolator interpolator =
AnimationUtils.loadInterpolator(context, R.interpolator.fast_out_extra_slow_in);
transition.setInterpolator(interpolator);
- // TODO(b/177480673): Update fade through threshold once (cl/362065364) is released
-
return transition;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 9c7aac1..4558a8a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -24,6 +24,10 @@
import android.bluetooth.BluetoothUuid;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -32,12 +36,16 @@
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
+import android.util.LruCache;
+import android.util.Pair;
import androidx.annotation.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.settingslib.R;
import com.android.settingslib.Utils;
+import com.android.settingslib.utils.ThreadUtils;
+import com.android.settingslib.widget.AdaptiveOutlineDrawable;
import java.util.ArrayList;
import java.util.Collection;
@@ -100,6 +108,8 @@
private boolean mIsHearingAidProfileConnectedFail = false;
// Group second device for Hearing Aid
private CachedBluetoothDevice mSubDevice;
+ @VisibleForTesting
+ LruCache<String, BitmapDrawable> mDrawableCache;
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
@@ -131,6 +141,19 @@
mDevice = device;
fillData();
mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
+ initDrawableCache();
+ }
+
+ private void initDrawableCache() {
+ int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
+ int cacheSize = maxMemory / 8;
+
+ mDrawableCache = new LruCache<String, BitmapDrawable>(cacheSize) {
+ @Override
+ protected int sizeOf(String key, BitmapDrawable bitmap) {
+ return bitmap.getBitmap().getByteCount() / 1024;
+ }
+ };
}
/**
@@ -381,6 +404,7 @@
if (dev != null) {
final boolean successful = dev.removeBond();
if (successful) {
+ releaseLruCache();
if (BluetoothUtils.D) {
Log.d(TAG, "Command sent successfully:REMOVE_BOND " + describe(null));
}
@@ -500,7 +524,21 @@
}
void refresh() {
- dispatchAttributesChanged();
+ ThreadUtils.postOnBackgroundThread(() -> {
+ if (BluetoothUtils.isAdvancedDetailsHeader(mDevice)) {
+ Uri uri = BluetoothUtils.getUriMetaData(getDevice(),
+ BluetoothDevice.METADATA_MAIN_ICON);
+ if (uri != null && mDrawableCache.get(uri.toString()) == null) {
+ mDrawableCache.put(uri.toString(),
+ (BitmapDrawable) BluetoothUtils.getBtDrawableWithDescription(
+ mContext, this).first);
+ }
+ }
+
+ ThreadUtils.postOnMainThread(() -> {
+ dispatchAttributesChanged();
+ });
+ });
}
public void setJustDiscovered(boolean justDiscovered) {
@@ -1178,4 +1216,28 @@
mSubDevice.mJustDiscovered = tmpJustDiscovered;
fetchActiveDevices();
}
+
+ /**
+ * Get cached bluetooth icon with description
+ */
+ public Pair<Drawable, String> getDrawableWithDescription() {
+ Uri uri = BluetoothUtils.getUriMetaData(mDevice, BluetoothDevice.METADATA_MAIN_ICON);
+ if (BluetoothUtils.isAdvancedDetailsHeader(mDevice) && uri != null) {
+ BitmapDrawable drawable = mDrawableCache.get(uri.toString());
+ if (drawable != null) {
+ Resources resources = mContext.getResources();
+ return new Pair<>(new AdaptiveOutlineDrawable(
+ resources, drawable.getBitmap()),
+ BluetoothUtils.getBtClassDrawableWithDescription(mContext, this).second);
+ }
+
+ refresh();
+ }
+
+ return BluetoothUtils.getBtRainbowDrawableWithDescription(mContext, this);
+ }
+
+ void releaseLruCache() {
+ mDrawableCache.evictAll();
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 53a99ab..38172f7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -35,6 +35,7 @@
import com.android.settingslib.R;
import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
+import com.android.settingslib.widget.AdaptiveOutlineDrawable;
import org.junit.Before;
import org.junit.Test;
@@ -957,4 +958,41 @@
// Should not crash
}
+
+ @Test
+ public void getDrawableWithDescription_isAdvancedDevice_returnAdvancedIcon() {
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_MAIN_ICON))
+ .thenReturn("fake_uri".getBytes());
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
+ .thenReturn("true".getBytes());
+
+ mCachedDevice.refresh();
+
+ assertThat(mCachedDevice.getDrawableWithDescription().first).isInstanceOf(
+ AdaptiveOutlineDrawable.class);
+ }
+
+ @Test
+ public void getDrawableWithDescription_isNotAdvancedDevice_returnBluetoothIcon() {
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
+ .thenReturn("false".getBytes());
+
+ mCachedDevice.refresh();
+
+ assertThat(mCachedDevice.getDrawableWithDescription().first).isNotInstanceOf(
+ AdaptiveOutlineDrawable.class);
+ }
+
+ @Test
+ public void releaseLruCache_lruCacheShouldBeRelease() {
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_MAIN_ICON))
+ .thenReturn("fake_uri".getBytes());
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
+ .thenReturn("true".getBytes());
+
+ mCachedDevice.refresh();
+ mCachedDevice.releaseLruCache();
+
+ assertThat(mCachedDevice.mDrawableCache.size()).isEqualTo(0);
+ }
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index c0e4df5..8f7f1fa 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -138,6 +138,7 @@
new InclusiveIntegerRangeValidator(
/* first= */Global.ONE_HANDED_KEYGUARD_SIDE_LEFT,
/* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT));
+ VALIDATORS.put(Global.DISABLE_WINDOW_BLURS, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 635434b..2f54e21 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -553,6 +553,9 @@
dumpSetting(s, p,
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
GlobalSettingsProto.Development.ENABLE_NON_RESIZABLE_MULTI_WINDOW);
+ dumpSetting(s, p,
+ Settings.Global.DISABLE_WINDOW_BLURS,
+ GlobalSettingsProto.Development.DISABLE_WINDOW_BLURS);
p.end(developmentToken);
final long deviceToken = p.start(GlobalSettingsProto.DEVICE);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 150d10d..22e38f4 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -231,6 +231,7 @@
Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR,
Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH,
Settings.Global.DEVICE_DEMO_MODE,
+ Settings.Global.DISABLE_WINDOW_BLURS,
Settings.Global.BATTERY_SAVER_CONSTANTS,
Settings.Global.BATTERY_TIP_CONSTANTS,
Settings.Global.DEFAULT_SM_DP_PLUS,
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 947ae8a..6d6bc07 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -191,23 +191,11 @@
fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {}
/**
- * The animation was cancelled remotely. Note that [onLaunchAnimationEnd] will still be
- * called after this if the animation was already started, i.e. if [onLaunchAnimationStart]
- * was called before the cancellation.
+ * The animation was cancelled. Note that [onLaunchAnimationEnd] will still be called after
+ * this if the animation was already started, i.e. if [onLaunchAnimationStart] was called
+ * before the cancellation.
*/
fun onLaunchAnimationCancelled() {}
-
- /**
- * The remote animation was not started within the expected time. It timed out and will
- * never [start][onLaunchAnimationStart].
- */
- fun onLaunchAnimationTimedOut() {}
-
- /**
- * The animation was aborted because the opening window was not found. It will never
- * [start][onLaunchAnimationStart].
- */
- fun onLaunchAnimationAborted() {}
}
/** The state of an expandable view during an [ActivityLaunchAnimator] animation. */
@@ -332,7 +320,7 @@
if (window == null) {
removeTimeout()
invokeCallback(iCallback)
- controller.onLaunchAnimationAborted()
+ controller.onLaunchAnimationCancelled()
return
}
@@ -486,7 +474,7 @@
}
timedOut = true
- controller.onLaunchAnimationTimedOut()
+ controller.onLaunchAnimationCancelled()
}
override fun onAnimationCancelled() {
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index 4fe48c9..8ead0e1 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -16,8 +16,12 @@
package com.android.systemui.plugins;
+import android.app.PendingIntent;
+import android.app.smartspace.SmartspaceAction;
import android.app.smartspace.SmartspaceTarget;
+import android.content.Intent;
import android.os.Parcelable;
+import android.view.View;
import android.view.ViewGroup;
import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -68,5 +72,33 @@
* Range [0.0 - 1.0] when transitioning from Lockscreen to/from AOD
*/
void setDozeAmount(float amount);
+
+ /**
+ * Overrides how Intents/PendingIntents gets launched. Mostly to support auth from
+ * the lockscreen.
+ */
+ void setIntentStarter(IntentStarter intentStarter);
+
+ /**
+ * When on the lockscreen, use the FalsingManager to help detect errant touches
+ */
+ void setFalsingManager(FalsingManager falsingManager);
+ }
+
+ /** Interface for launching Intents, which can differ on the lockscreen */
+ interface IntentStarter {
+ default void startFromAction(SmartspaceAction action, View v) {
+ if (action.getIntent() != null) {
+ startIntent(v, action.getIntent());
+ } else if (action.getPendingIntent() != null) {
+ startPendingIntent(action.getPendingIntent());
+ }
+ }
+
+ /** Start the intent */
+ void startIntent(View v, Intent i);
+
+ /** Start the PendingIntent */
+ void startPendingIntent(PendingIntent pi);
}
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
index 4142e51..b75252b 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
@@ -58,7 +58,6 @@
/** Returns true if the gesture should be rejected. */
boolean isFalseTouch(int interactionType);
-
/**
* Does basic checking to see if gesture looks like a tap.
*
@@ -127,8 +126,19 @@
/** Removes a {@link FalsingBeliefListener}. */
void removeFalsingBeliefListener(FalsingBeliefListener listener);
+ /** Adds a {@link FalsingTapListener}. */
+ void addTapListener(FalsingTapListener falsingTapListener);
+
+ /** Removes a {@link FalsingTapListener}. */
+ void removeTapListener(FalsingTapListener falsingTapListener);
+
/** Listener that is alerted when falsing belief level crosses a predfined threshold. */
interface FalsingBeliefListener {
void onFalse();
}
+
+ /** Listener that is alerted when a double tap is required to confirm a single tap. */
+ interface FalsingTapListener {
+ void onDoubleTapRequired();
+ }
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index fffcafb..4d4c909 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -14,7 +14,6 @@
package com.android.systemui.plugins.qs;
-import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -57,7 +56,6 @@
void setQsExpansion(float qsExpansionFraction, float headerTranslation);
void setHeaderListening(boolean listening);
void notifyCustomizeChanged();
-
void setContainer(ViewGroup container);
void setExpandClickListener(OnClickListener onClickListener);
@@ -75,6 +73,16 @@
return isShowingDetail();
}
+ /**
+ * If QS should translate as we pull it down, or if it should be static.
+ */
+ void setTranslateWhileExpanding(boolean shouldTranslate);
+
+ /**
+ * A rounded corner clipping that makes QS feel as if it were behind everything.
+ */
+ void setFancyClipping(int top, int bottom, int cornerRadius, boolean visible);
+
@ProvidesInterface(version = HeightListener.VERSION)
interface HeightListener {
int VERSION = 1;
diff --git a/packages/SystemUI/res-keyguard/color/notification_background_dimmed_color.xml b/packages/SystemUI/res-keyguard/color/notification_background_dimmed_color.xml
deleted file mode 100644
index 3345e6e..0000000
--- a/packages/SystemUI/res-keyguard/color/notification_background_dimmed_color.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:alpha="0.7" android:color="?android:attr/colorBackground" />
-</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
index c5ba3d2..7f645ba 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
@@ -20,12 +20,14 @@
<!-- This is a view that shows general status information in Keyguard. -->
<com.android.keyguard.KeyguardStatusView
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/keyguard_status_view"
android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal|top">
+ systemui:layout_constraintStart_toStartOf="parent"
+ systemui:layout_constraintEnd_toEndOf="parent"
+ systemui:layout_constraintTop_toTopOf="parent"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/status_view_container"
android:layout_width="match_parent"
@@ -70,5 +72,11 @@
android:letterSpacing="0.05"
android:ellipsize="marquee"
android:singleLine="true" />
+ <FrameLayout
+ android:id="@+id/status_view_media_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/qs_media_padding"
+ />
</LinearLayout>
</com.android.keyguard.KeyguardStatusView>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index 696f215..33aa228 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -100,7 +100,7 @@
<string name="kg_password_puk_failed" msgid="6778867411556937118">"Operasi PUK SIM gagal!"</string>
<string name="kg_pin_accepted" msgid="1625501841604389716">"Kode Diterima!"</string>
<string name="keyguard_carrier_default" msgid="6359808469637388586">"Tidak ada layanan."</string>
- <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Beralih metode masukan"</string>
+ <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Beralih metode input"</string>
<string name="airplane_mode" msgid="2528005343938497866">"Mode pesawat"</string>
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pola diperlukan setelah perangkat dimulai ulang"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN diperlukan setelah perangkat dimulai ulang"</string>
diff --git a/packages/SystemUI/res-keyguard/values/integers.xml b/packages/SystemUI/res-keyguard/values/integers.xml
index 6f14dc9b..c6e90c0 100644
--- a/packages/SystemUI/res-keyguard/values/integers.xml
+++ b/packages/SystemUI/res-keyguard/values/integers.xml
@@ -20,4 +20,11 @@
0x50 = bottom, 0x01 = center_horizontal -->
<integer name="keyguard_host_view_gravity">0x51</integer>
+
+ <!-- Gravity for the keyguard when it is in one-handed mode. This is ignored unless
+ can_use_one_handed_bouncer is true, _and_ the one handed bouncer is enabled in the device
+ config (com.android.internal.R.bool.config_enableOneHandedKeyguard)
+
+ 0x50 = bottom, 0x01 = center_horizontal -->
+ <integer name="keyguard_host_view_one_handed_gravity">0x51</integer>
</resources>
diff --git a/packages/SystemUI/res/color/qs_security_footer_background_stroke.xml b/packages/SystemUI/res/color/qs_security_footer_background_stroke.xml
new file mode 100644
index 0000000..aa4d4e8
--- /dev/null
+++ b/packages/SystemUI/res/color/qs_security_footer_background_stroke.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral1_100" android:alpha="0.8" />
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/notification_material_bg_dim.xml b/packages/SystemUI/res/drawable/notification_material_bg_dim.xml
deleted file mode 100644
index 1127d3c..0000000
--- a/packages/SystemUI/res/drawable/notification_material_bg_dim.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2014 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android">
- <item>
- <shape>
- <solid android:color="@color/notification_background_dimmed_color" />
- </shape>
- </item>
-</ripple>
diff --git a/packages/SystemUI/res/drawable/qs_security_footer_background.xml b/packages/SystemUI/res/drawable/qs_security_footer_background.xml
new file mode 100644
index 0000000..7d370e9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_security_footer_background.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetTop="@dimen/qs_security_footer_background_inset"
+ android:insetBottom="@dimen/qs_security_footer_background_inset"
+ >
+ <ripple
+ android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="@android:color/white"/>
+ <corners android:radius="@dimen/qs_security_footer_corner_radius"/>
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="rectangle">
+ <stroke android:width="1dp"
+ android:color="@color/qs_security_footer_background_stroke"/>
+ <corners android:radius="@dimen/qs_security_footer_corner_radius"/>
+ </shape>
+ </item>
+ </ripple>
+</inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/hybrid_conversation_notification.xml b/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
index 214c44a..335e0a4 100644
--- a/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
+++ b/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
@@ -26,21 +26,22 @@
<FrameLayout
android:layout_width="@*android:dimen/conversation_content_start"
- android:layout_height="25dp"
+ android:layout_height="@dimen/conversation_single_line_face_pile_size"
+ android:paddingHorizontal="16dp"
>
<ImageView
android:id="@*android:id/conversation_icon"
- android:layout_width="20dp"
- android:layout_height="20dp"
- android:layout_gravity="center"
+ android:layout_width="@dimen/conversation_single_line_avatar_size"
+ android:layout_height="@dimen/conversation_single_line_avatar_size"
+ android:layout_gravity="center_vertical|end"
/>
<ViewStub
android:id="@*android:id/conversation_face_pile"
android:layout="@*android:layout/conversation_face_pile_layout"
- android:layout_width="25dp"
- android:layout_height="25dp"
- android:layout_gravity="center"
+ android:layout_width="@dimen/conversation_single_line_face_pile_size"
+ android:layout_height="@dimen/conversation_single_line_face_pile_size"
+ android:layout_gravity="center_vertical|end"
/>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
index 7e944162..f4a7434 100644
--- a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
+++ b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
@@ -18,6 +18,7 @@
<!-- Layout for media recommendations inside QSPanel carousel -->
<com.android.systemui.util.animation.TransitionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/media_recommendations"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -84,4 +85,99 @@
android:layout_width="@dimen/qs_aa_media_rec_icon_size"
android:layout_height="@dimen/qs_aa_media_rec_icon_size" />
+ <!-- Constraints are set here as they are the same regardless of host -->
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:id="@+id/recommendation_text"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textColor="?android:attr/textColorSecondary"
+ android:text="@string/controls_media_title"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/remove_text"
+ app:layout_constraintVertical_chainStyle="spread_inside"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:id="@+id/remove_text"
+ android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:singleLine="true"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/controls_media_close_session"
+ app:layout_constraintTop_toBottomOf="@id/recommendation_text"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/settings"/>
+
+ <FrameLayout
+ android:id="@+id/settings"
+ android:background="@drawable/qs_media_light_source"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+ android:paddingBottom="@dimen/qs_media_panel_outer_padding"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/remove_text">
+
+ <TextView
+ android:layout_gravity="bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/controls_media_settings_button" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/cancel"
+ android:background="@drawable/qs_media_light_source"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:paddingBottom="@dimen/qs_media_panel_outer_padding"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/dismiss" >
+
+ <TextView
+ android:layout_gravity="bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/cancel" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/dismiss"
+ android:background="@drawable/qs_media_light_source"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:paddingBottom="@dimen/qs_media_panel_outer_padding"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <TextView
+ android:layout_gravity="bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/controls_media_dismiss_button"
+ />
+ </FrameLayout>
+
</com.android.systemui.util.animation.TransitionLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 1125092..ea644cf 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -24,7 +24,6 @@
android:clipChildren="true"
android:clipToPadding="true"
android:orientation="vertical"
- android:background="?android:attr/colorBackground"
android:paddingStart="12dp">
<!-- Package Info -->
diff --git a/packages/SystemUI/res/layout/ongoing_call_chip.xml b/packages/SystemUI/res/layout/ongoing_call_chip.xml
index c90fc31..a5e7f5d 100644
--- a/packages/SystemUI/res/layout/ongoing_call_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_call_chip.xml
@@ -23,7 +23,6 @@
android:background="@drawable/ongoing_call_chip_bg"
android:paddingStart="@dimen/ongoing_call_chip_side_padding"
android:paddingEnd="@dimen/ongoing_call_chip_side_padding"
- android:visibility="gone"
>
<ImageView
diff --git a/packages/SystemUI/res/layout/people_space_placeholder_layout.xml b/packages/SystemUI/res/layout/people_space_placeholder_layout.xml
index 2402bd7..abb771b 100644
--- a/packages/SystemUI/res/layout/people_space_placeholder_layout.xml
+++ b/packages/SystemUI/res/layout/people_space_placeholder_layout.xml
@@ -26,7 +26,7 @@
android:orientation="horizontal"
android:gravity="center"
android:layout_gravity="top"
- android:paddingVertical="16dp"
+ android:paddingVertical="8dp"
android:paddingHorizontal="16dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 343b398..93a4715 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -50,7 +50,8 @@
android:focusable="true"
android:gravity="center_vertical"
android:singleLine="true"
- android:textAppearance="@style/TextAppearance.QS.Status"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAppearance="@style/TextAppearance.QS.Build"
android:visibility="gone" />
<com.android.systemui.qs.PageIndicator
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 1f90476..d8bb7e6 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -44,14 +44,6 @@
android:layout_weight="1"
/>
- <!-- Will hold security footer in landscape with media -->
- <FrameLayout
- android:id="@+id/header_text_container"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:gravity="center"
- />
-
<include layout="@layout/qs_carrier_group"
android:id="@+id/carrier_group"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/quick_settings_footer.xml b/packages/SystemUI/res/layout/quick_settings_footer.xml
deleted file mode 100644
index db712e4..0000000
--- a/packages/SystemUI/res/layout/quick_settings_footer.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<com.android.systemui.util.NeverExactlyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:minHeight="48dp"
- android:clickable="true"
- android:paddingBottom="@dimen/qs_tile_padding_top"
- android:paddingTop="@dimen/qs_tile_padding_top"
- android:paddingStart="@dimen/qs_footer_padding_start"
- android:paddingEnd="@dimen/qs_footer_padding_end"
- android:gravity="center_vertical"
- android:layout_gravity="center_vertical|center_horizontal"
- android:background="@android:color/transparent">
-
- <ImageView
- android:id="@+id/primary_footer_icon"
- android:layout_width="@dimen/qs_footer_icon_size"
- android:layout_height="@dimen/qs_footer_icon_size"
- android:gravity="start"
- android:layout_marginEnd="8dp"
- android:contentDescription="@null"
- android:tint="?android:attr/textColorPrimary" />
-
- <com.android.systemui.util.AutoMarqueeTextView
- android:id="@+id/footer_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:textAppearance="@style/TextAppearance.QS.TileLabel"
- android:textColor="?android:attr/textColorPrimary"/>
-
- <ImageView
- android:id="@+id/footer_icon"
- android:layout_width="@dimen/qs_footer_icon_size"
- android:layout_height="@dimen/qs_footer_icon_size"
- android:layout_marginStart="8dp"
- android:contentDescription="@null"
- android:src="@drawable/ic_info_outline"
- android:tint="?android:attr/textColorPrimary" />
-
-</com.android.systemui.util.NeverExactlyLinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_security_footer.xml b/packages/SystemUI/res/layout/quick_settings_security_footer.xml
new file mode 100644
index 0000000..de65fa0
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_security_footer.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.systemui.util.DualHeightHorizontalLinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_security_footer_height"
+ android:clickable="true"
+ android:padding="@dimen/qs_footer_padding"
+ android:gravity="center_vertical"
+ android:layout_gravity="center_vertical|center_horizontal"
+ android:layout_marginVertical="@dimen/qs_security_footer_vertical_margin"
+ android:background="@drawable/qs_security_footer_background"
+ systemui:singleLineHeight="@dimen/qs_security_footer_single_line_height"
+ systemui:textViewId="@id/footer_text"
+ >
+
+ <ImageView
+ android:id="@+id/primary_footer_icon"
+ android:layout_width="@dimen/qs_footer_icon_size"
+ android:layout_height="@dimen/qs_footer_icon_size"
+ android:gravity="start"
+ android:layout_marginEnd="12dp"
+ android:contentDescription="@null"
+ android:tint="?android:attr/textColorSecondary" />
+
+ <TextView
+ android:id="@+id/footer_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:maxLines="@integer/qs_security_footer_maxLines"
+ android:ellipsize="end"
+ android:textAppearance="@style/TextAppearance.QS.SecurityFooter"
+ android:textColor="?android:attr/textColorSecondary"/>
+
+ <ImageView
+ android:id="@+id/footer_icon"
+ android:layout_width="@dimen/qs_footer_icon_size"
+ android:layout_height="@dimen/qs_footer_icon_size"
+ android:layout_marginStart="8dp"
+ android:contentDescription="@null"
+ android:src="@*android:drawable/ic_chevron_end"
+ android:tint="?android:attr/textColorSecondary" />
+
+</com.android.systemui.util.DualHeightHorizontalLinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
index 22cf2cb..d0e3d3c 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
@@ -55,6 +55,16 @@
android:layout_gravity="center_vertical|center_horizontal"
android:visibility="gone" />
+ <!-- Will hold security footer in landscape with media -->
+ <FrameLayout
+ android:id="@+id/header_text_container"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ android:gravity="center"
+ />
+
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 46a698a..52995ea 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -37,10 +37,6 @@
android:layout_height="match_parent"
android:layout_width="match_parent" />
- <include
- layout="@layout/keyguard_status_view"
- android:visibility="gone" />
-
<com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -49,6 +45,10 @@
android:clipToPadding="false"
android:clipChildren="false">
+ <include
+ layout="@layout/keyguard_status_view"
+ android:visibility="gone"/>
+
<include layout="@layout/dock_info_overlay" />
<FrameLayout
diff --git a/packages/SystemUI/res/layout/status_bar_notification_shelf.xml b/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
index 781c015..87a1bbb 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
@@ -27,10 +27,6 @@
android:id="@+id/backgroundNormal"
android:layout_width="match_parent"
android:layout_height="match_parent" />
- <com.android.systemui.statusbar.notification.row.NotificationBackgroundView
- android:id="@+id/backgroundDimmed"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
<com.android.systemui.statusbar.phone.NotificationIconContainer
android:id="@+id/content"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index 12c864c..bea50e8 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -43,7 +43,7 @@
android:visibility="invisible" />
</com.android.systemui.statusbar.BackDropView>
- <com.android.systemui.statusbar.ScrimView
+ <com.android.systemui.scrim.ScrimView
android:id="@+id/scrim_behind"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -51,7 +51,7 @@
sysui:ignoreRightInset="true"
/>
- <com.android.systemui.statusbar.ScrimView
+ <com.android.systemui.scrim.ScrimView
android:id="@+id/scrim_notifications"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -72,7 +72,7 @@
<include layout="@layout/brightness_mirror_container" />
- <com.android.systemui.statusbar.ScrimView
+ <com.android.systemui.scrim.ScrimView
android:id="@+id/scrim_in_front"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml
index 50b2f20..e5e8fe6 100644
--- a/packages/SystemUI/res/layout/udfps_view.xml
+++ b/packages/SystemUI/res/layout/udfps_view.xml
@@ -20,7 +20,8 @@
android:id="@+id/udfps_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- systemui:sensorTouchAreaCoefficient="0.5">
+ systemui:sensorTouchAreaCoefficient="0.5"
+ android:contentDescription="@string/accessibility_fingerprint_label">
<ViewStub
android:id="@+id/animation_view"
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 5f50fd4..46e7d71 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -30,6 +30,12 @@
-->
<dimen name="qs_customize_header_min_height">44dp</dimen>
+ <dimen name="qs_security_footer_single_line_height">@*android:dimen/quick_qs_offset_height</dimen>
+ <dimen name="qs_footer_padding">14dp</dimen>
+ <dimen name="qs_security_footer_vertical_margin">0dp</dimen>
+ <dimen name="qs_security_footer_background_inset">12dp</dimen>
+ <dimen name="qs_security_footer_corner_radius">28dp</dimen>
+
<dimen name="battery_detail_graph_space_top">9dp</dimen>
<dimen name="battery_detail_graph_space_bottom">9dp</dimen>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index f489fe8..eb72442 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -189,5 +189,11 @@
<attr name="borderThickness" format="dimension" />
<attr name="borderColor" format="color" />
</declare-styleable>
+
+ <declare-styleable name="DualHeightHorizontalLinearLayout">
+ <attr name="singleLineHeight" format="dimension" />
+ <attr name="singleLineVerticalPadding" format="dimension" />
+ <attr name="textViewId" format="reference" />
+ </declare-styleable>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index fff4a1b..f7578cbd 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -605,13 +605,18 @@
<dimen name="qs_header_carrier_separator_width">6dp</dimen>
<dimen name="qs_status_separator">32dp</dimen>
<dimen name="qs_carrier_margin_width">4dp</dimen>
- <dimen name="qs_footer_padding_start">16dp</dimen>
- <dimen name="qs_footer_padding_end">16dp</dimen>
- <dimen name="qs_footer_icon_size">16dp</dimen>
+ <dimen name="qs_footer_icon_size">20dp</dimen>
<dimen name="qs_paged_tile_layout_padding_bottom">0dp</dimen>
<dimen name="qs_header_top_padding">15dp</dimen>
<dimen name="qs_header_bottom_padding">14dp</dimen>
+ <dimen name="qs_footer_padding">20dp</dimen>
+ <dimen name="qs_security_footer_height">88dp</dimen>
+ <dimen name="qs_security_footer_single_line_height">48dp</dimen>
+ <dimen name="qs_security_footer_vertical_margin">8dp</dimen>
+ <dimen name="qs_security_footer_background_inset">0dp</dimen>
+ <dimen name="qs_security_footer_corner_radius">28dp</dimen>
+
<dimen name="qs_notif_collapsed_space">64dp</dimen>
<dimen name="qs_container_bottom_padding">24dp</dimen>
@@ -691,8 +696,11 @@
<!-- Size of the face pile shown on one-line (children of a group) conversation notifications -->
<dimen name="conversation_single_line_face_pile_size">25dp</dimen>
+ <!-- Size of the avatars within a face pile shown on one-line (children of a group) conversation notifications -->
+ <dimen name="conversation_single_line_face_pile_avatar_size">17dp</dimen>
+
<!-- Size of an avatar shown on one-line (children of a group) conversation notifications -->
- <dimen name="conversation_single_line_avatar_size">20dp</dimen>
+ <dimen name="conversation_single_line_avatar_size">24dp</dimen>
<!-- Border width for avatars in the face pile shown on one-line (children of a group) conversation notifications -->
<dimen name="conversation_single_line_face_pile_protection_width">1dp</dimen>
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
index b50b5c1..116403c 100644
--- a/packages/SystemUI/res/values/integers.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -22,6 +22,8 @@
<integer name="qs_footer_actions_width">0</integer>
<integer name="qs_footer_actions_weight">1</integer>
+ <integer name="qs_security_footer_maxLines">2</integer>
+
<integer name="magnification_default_scale">2</integer>
<!-- The position of the volume dialog on the screen.
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8a3ba4b..a9f6946 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -338,6 +338,8 @@
<string name="accessibility_voice_assist_button">Voice Assist</string>
<!-- Content description of the unlock button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_unlock_button">Unlock</string>
+ <!-- Content description of the lock icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_lock_icon">Device locked</string>
<!-- Content description hint of the unlock button when fingerprint is on (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_waiting_for_fingerprint">Waiting for fingerprint</string>
<!-- Accessibility action of the unlock button when fingerpint is on (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -2905,15 +2907,15 @@
<!-- Status text on the Conversation widget for a birthday today [CHAR LIMIT=20] -->
<string name="birthday_status">Birthday</string>
<!-- Content description text on the Conversation widget for a birthday today [CHAR LIMIT=150] -->
- <string name="birthday_status_content_description">It\’s <xliff:g id="name" example="Anna">%1$s</xliff:g>\’s birthday</string>
+ <string name="birthday_status_content_description">It\'s <xliff:g id="name" example="Anna">%1$s</xliff:g>\’s birthday</string>
<!-- Status text on the Conversation widget for an upcoming birthday [CHAR LIMIT=20] -->
<string name="upcoming_birthday_status">Birthday soon</string>
<!-- Content description text on the Conversation widget for an upcoming birthday [CHAR LIMIT=150] -->
- <string name="upcoming_birthday_status_content_description">It\’s <xliff:g id="name" example="Anna">%1$s</xliff:g>\’s birthday soon</string>
+ <string name="upcoming_birthday_status_content_description">It\'s <xliff:g id="name" example="Anna">%1$s</xliff:g>\’s birthday soon</string>
<!-- Status text on the Conversation widget for an anniversary [CHAR LIMIT=20] -->
<string name="anniversary_status">Anniversary</string>
<!-- Content description text on the Conversation widget for an anniversary [CHAR LIMIT=150] -->
- <string name="anniversary_status_content_description">It\’s <xliff:g id="name" example="Anna">%1$s</xliff:g>\’s anniversary</string>
+ <string name="anniversary_status_content_description">It\'s <xliff:g id="name" example="Anna">%1$s</xliff:g>\’s anniversary</string>
<!-- Status text on the Conversation widget for sharing location [CHAR LIMIT=20] -->
<string name="location_status">Sharing location</string>
<!-- Content description text on the Conversation widget for sharing location [CHAR LIMIT=150] -->
@@ -2958,4 +2960,15 @@
<!-- Secondary label for alarm tile when there is no next alarm information [CHAR LIMIT=20] -->
<string name="qs_alarm_tile_no_alarm">No alarm set</string>
+
+ <!-- Accessibility label for fingerprint sensor [CHAR LIMIT=NONE] -->
+ <string name="accessibility_fingerprint_label">Fingerprint sensor</string>
+ <!-- Accessibility label for disabled udfps sensor [CHAR LIMIT=NONE] -->
+ <string name="accessibility_udfps_disabled_button">Fingerprint sensor disabled</string>
+ <!-- Accessibility action for tapping on an affordance that will bring up the user's
+ pin/pattern/password bouncer (ie: "Double tap to authenticate") [CHAR LIMIT=NONE] -->
+ <string name="accessibility_authenticate_hint">authenticate</string>
+ <!-- Accessibility action for tapping on an affordance on an unlocked lock screen (ie: "Double
+ tap to enter device") [CHAR LIMIT=NONE] -->
+ <string name="accessibility_enter_hint">enter device</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 885227b..2e45acc 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -220,11 +220,21 @@
<item name="android:textSize">@dimen/celltile_rat_type_size</item>
</style>
+ <style name="TextAppearance.QS.SecurityFooter">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:textSize">@dimen/qs_tile_text_size</item>
+ </style>
+
<style name="TextAppearance.QS.Status" parent="TextAppearance.QS.TileLabel.Secondary">
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
<item name="android:textColor">@color/dark_mode_qs_icon_color_single_tone</item>
</style>
+ <style name="TextAppearance.QS.Build">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:textSize">14sp</item>
+ </style>
+
<style name="TextAppearance.DeviceManagementDialog">
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
diff --git a/packages/SystemUI/res/xml/people_space_widget_info.xml b/packages/SystemUI/res/xml/people_space_widget_info.xml
index 68e6ca8..cce27e7 100644
--- a/packages/SystemUI/res/xml/people_space_widget_info.xml
+++ b/packages/SystemUI/res/xml/people_space_widget_info.xml
@@ -16,7 +16,7 @@
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="136dp"
- android:minHeight="55dp"
+ android:targetCellHeight="1"
android:minResizeWidth="60dp"
android:minResizeHeight="50dp"
android:maxResizeHeight="207dp"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
index 1a4e2d1..2b35bcd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
@@ -385,10 +385,8 @@
}
Intent i = new Intent(PluginManagerImpl.DISABLE_PLUGIN).setData(
Uri.parse("package://" + component.flattenToString()));
- // TODO(b/174161910) Please replace FLAG_MUTABLE_UNAUDITED below
- // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i,
- PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ PendingIntent.FLAG_IMMUTABLE);
nb.addAction(new Action.Builder(null, "Disable plugin", pi).build());
mContext.getSystemService(NotificationManager.class)
.notify(SystemMessage.NOTE_PLUGIN, nb.build());
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
index 4e0204b..22d934e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
@@ -25,6 +25,7 @@
import static android.view.WindowManager.TransitionOldType;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
+import android.annotation.SuppressLint;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -241,10 +242,16 @@
final Runnable animationFinishedCallback = new Runnable() {
@Override
+ @SuppressLint("NewApi")
public void run() {
try {
counterLauncher.cleanUp(info.getRootLeash());
counterWallpaper.cleanUp(info.getRootLeash());
+ // Release surface references now. This is apparently to free GPU
+ // memory while doing quick operations (eg. during CTS).
+ for (int i = 0; i < info.getChanges().size(); ++i) {
+ info.getChanges().get(i).getLeash().release();
+ }
finishCallback.onTransitionFinished(null /* wct */);
} catch (RemoteException e) {
Log.e("ActivityOptionsCompat", "Failed to call app controlled animation"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 7d1c0a6..351dfd5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -24,6 +24,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.Parcelable;
@@ -127,7 +128,7 @@
}
t.apply();
final RecentsAnimationControllerCompat wrapControl =
- new RecentsControllerWrap(controller, finishedCallback, pausingTask);
+ new RecentsControllerWrap(controller, info, finishedCallback, pausingTask);
recents.onAnimationStart(wrapControl, apps, wallpapers, new Rect(0, 0, 0, 0),
new Rect());
}
@@ -161,10 +162,12 @@
private final RecentsAnimationControllerCompat mWrapped;
private final IRemoteTransitionFinishedCallback mFinishCB;
private final WindowContainerToken mPausingTask;
+ private final TransitionInfo mInfo;
- RecentsControllerWrap(RecentsAnimationControllerCompat wrapped,
+ RecentsControllerWrap(RecentsAnimationControllerCompat wrapped, TransitionInfo info,
IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask) {
mWrapped = wrapped;
+ mInfo = info;
mFinishCB = finishCB;
mPausingTask = pausingTask;
}
@@ -192,7 +195,9 @@
}
}
- @Override public void finish(boolean toHome, boolean sendUserLeaveHint) {
+ @Override
+ @SuppressLint("NewApi")
+ public void finish(boolean toHome, boolean sendUserLeaveHint) {
try {
if (!toHome && mPausingTask != null) {
// The gesture went back to opening the app rather than continuing with
@@ -207,6 +212,11 @@
Log.e("RemoteTransitionCompat", "Failed to call animation finish callback", e);
}
if (mWrapped != null) mWrapped.finish(toHome, sendUserLeaveHint);
+ // Release surface references now. This is apparently to free GPU
+ // memory while doing quick operations (eg. during CTS).
+ for (int i = 0; i < mInfo.getChanges().size(); ++i) {
+ mInfo.getChanges().get(i).getLeash().release();
+ }
}
@Override public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index f2bebce..5559a18 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -19,10 +19,12 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import android.app.PendingIntent;
import android.app.WallpaperManager;
import android.app.smartspace.SmartspaceConfig;
import android.app.smartspace.SmartspaceManager;
import android.app.smartspace.SmartspaceSession;
+import android.content.Intent;
import android.content.res.Resources;
import android.text.TextUtils;
import android.text.format.DateFormat;
@@ -39,8 +41,11 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.IntentStarter;
import com.android.systemui.plugins.ClockPlugin;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.notification.AnimatableProperty;
@@ -87,6 +92,8 @@
private SmartspaceSession.OnTargetsAvailableListener mSmartspaceCallback;
private int mWallpaperTextColor;
private ConfigurationController mConfigurationController;
+ private ActivityStarter mActivityStarter;
+ private FalsingManager mFalsingManager;
/**
* Listener for changes to the color palette.
@@ -138,7 +145,9 @@
@Main Executor uiExecutor,
BatteryController batteryController,
ConfigurationController configurationController,
- SystemUIFactory systemUIFactory) {
+ SystemUIFactory systemUIFactory,
+ ActivityStarter activityStarter,
+ FalsingManager falsingManager) {
super(keyguardClockSwitch);
mStatusBarStateController = statusBarStateController;
mColorExtractor = colorExtractor;
@@ -151,6 +160,8 @@
mBatteryController = batteryController;
mConfigurationController = configurationController;
mSystemUIFactory = systemUIFactory;
+ mActivityStarter = activityStarter;
+ mFalsingManager = falsingManager;
}
/**
@@ -200,6 +211,16 @@
mSmartspaceView = smartspaceDataPlugin.getView(mView);
mSmartspaceView.registerDataProvider(smartspaceDataPlugin);
+ mSmartspaceView.setIntentStarter(new IntentStarter() {
+ public void startIntent(View v, Intent i) {
+ mActivityStarter.startActivity(i, true /* dismissShade */);
+ }
+
+ public void startPendingIntent(PendingIntent pi) {
+ mActivityStarter.startPendingIntentDismissingKeyguard(pi);
+ }
+ });
+ mSmartspaceView.setFalsingManager(mFalsingManager);
updateWallpaperColor();
View asView = (View) mSmartspaceView;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
index 31f1332..d06c8bc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -475,7 +475,18 @@
* configuration.
*/
public void updateResources() {
- int gravity = mView.getResources().getInteger(R.integer.keyguard_host_view_gravity);
+ int gravity;
+
+ Resources resources = mView.getResources();
+
+ if (resources.getBoolean(R.bool.can_use_one_handed_bouncer)
+ && resources.getBoolean(
+ com.android.internal.R.bool.config_enableOneHandedKeyguard)) {
+ gravity = resources.getInteger(
+ R.integer.keyguard_host_view_one_handed_gravity);
+ } else {
+ gravity = resources.getInteger(R.integer.keyguard_host_view_gravity);
+ }
// 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),
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 9df7734..3ab2cca 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -35,6 +35,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.R;
+import com.android.systemui.statusbar.CrossFadeHelper;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -44,6 +45,7 @@
* - keyguard clock
* - logout button (on certain managed devices)
* - owner information (if set)
+ * - media player (split shade mode only)
*/
public class KeyguardStatusView extends GridLayout {
private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -60,6 +62,7 @@
private KeyguardSliceView mKeyguardSlice;
private Runnable mPendingMarqueeStart;
private Handler mHandler;
+ private View mMediaHostContainer;
private float mDarkAmount = 0;
private int mTextColor;
@@ -148,6 +151,8 @@
mKeyguardSlice.setContentChangeListener(this::onSliceContentChanged);
onSliceContentChanged();
+ mMediaHostContainer = findViewById(R.id.status_view_media_container);
+
updateOwnerInfo();
updateDark();
}
@@ -223,6 +228,9 @@
}
mDarkAmount = darkAmount;
mClockView.setDarkAmount(darkAmount);
+ if (mMediaHostContainer.getVisibility() != View.GONE) {
+ CrossFadeHelper.fadeOut(mMediaHostContainer, darkAmount);
+ }
updateDark();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index fc80dbe..588f4bb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import android.graphics.Rect;
import android.os.UserHandle;
import android.util.Slog;
@@ -48,6 +49,7 @@
private final ConfigurationController mConfigurationController;
private final DozeParameters mDozeParameters;
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
+ private final Rect mClipBounds = new Rect();
private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
@@ -299,4 +301,17 @@
mView.updateLogoutView(shouldShowLogout());
}
};
+
+ /**
+ * Rect that specifies how KSV should be clipped, on its parent's coordinates.
+ */
+ public void setClipBounds(Rect clipBounds) {
+ if (clipBounds != null) {
+ mClipBounds.set(clipBounds.left, (int) (clipBounds.top - mView.getY()),
+ clipBounds.right, (int) (clipBounds.bottom - mView.getY()));
+ mView.setClipBounds(mClipBounds);
+ } else {
+ mView.setClipBounds(null);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
index 015c4e4..ecc8c00 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
@@ -146,6 +146,13 @@
void startPreHideAnimation(Runnable finishRunnable);
/**
+ * Blocks the current touch gesture from affecting the expansion amount of the notification
+ * panel. This is used after a completed unlock gesture to ignore further dragging before an
+ * ACTION_UP.
+ */
+ void blockPanelExpansionFromCurrentTouch();
+
+ /**
* @return the ViewRootImpl of the View where the Keyguard is mounted.
*/
ViewRootImpl getViewRootImpl();
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 66ea2ad..9b0ae6b 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -29,9 +29,12 @@
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import com.android.settingslib.Utils;
import com.android.systemui.Dumpable;
@@ -63,6 +66,7 @@
@NonNull private final KeyguardStateController mKeyguardStateController;
@NonNull private final FalsingManager mFalsingManager;
@NonNull private final AuthController mAuthController;
+ @NonNull private final AccessibilityManager mAccessibilityManager;
private boolean mHasUdfpsOrFaceAuthFeatures;
private boolean mUdfpsEnrolled;
@@ -93,19 +97,17 @@
@NonNull KeyguardStateController keyguardStateController,
@NonNull FalsingManager falsingManager,
@NonNull AuthController authController,
- @NonNull DumpManager dumpManager
+ @NonNull DumpManager dumpManager,
+ @NonNull AccessibilityManager accessibilityManager
) {
super(view);
- if (mView != null) {
- mView.setOnClickListener(v -> onAffordanceClick());
- mView.setOnLongClickListener(v -> onAffordanceClick());
- }
mStatusBarStateController = statusBarStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mAuthController = authController;
mKeyguardViewController = keyguardViewController;
mKeyguardStateController = keyguardStateController;
mFalsingManager = falsingManager;
+ mAccessibilityManager = accessibilityManager;
final Context context = view.getContext();
mButton = context.getResources().getDrawable(
@@ -122,6 +124,11 @@
}
@Override
+ protected void onInit() {
+ mView.setAccessibilityDelegate(mAccessibilityDelegate);
+ }
+
+ @Override
protected void onViewAttached() {
// we check this here instead of onInit since the FingeprintManager + FaceManager may not
// have started up yet onInit
@@ -163,6 +170,8 @@
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
mStatusBarStateController.addCallback(mStatusBarStateListener);
mKeyguardStateController.addCallback(mKeyguardStateCallback);
+ mAccessibilityManager.addTouchExplorationStateChangeListener(
+ mTouchExplorationStateChangeListener);
updateVisibility();
}
@@ -172,6 +181,8 @@
mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
mKeyguardStateController.removeCallback(mKeyguardStateCallback);
+ mAccessibilityManager.removeTouchExplorationStateChangeListener(
+ mTouchExplorationStateChangeListener);
}
public float getTop() {
@@ -210,20 +221,56 @@
mShowLockIcon = !mUdfpsEnrolled && !mCanDismissLockScreen && isLockScreen()
&& mFaceAuthEnrolled;
+ updateClickListener();
if (mShowButton) {
mView.setImageDrawable(mButton);
mView.setVisibility(View.VISIBLE);
+ mView.setContentDescription(getResources().getString(
+ R.string.accessibility_udfps_disabled_button));
} else if (mShowUnlockIcon) {
mView.setImageDrawable(mUnlockIcon);
mView.setVisibility(View.VISIBLE);
+ mView.setContentDescription(getResources().getString(
+ R.string.accessibility_unlock_button));
} else if (mShowLockIcon) {
mView.setImageDrawable(mLockIcon);
mView.setVisibility(View.VISIBLE);
+ mView.setContentDescription(getResources().getString(
+ R.string.accessibility_lock_icon));
} else {
mView.setVisibility(View.INVISIBLE);
+ mView.setContentDescription(null);
}
}
+ private final View.AccessibilityDelegate mAccessibilityDelegate =
+ new View.AccessibilityDelegate() {
+ private final AccessibilityNodeInfo.AccessibilityAction mAccessibilityAuthenticateHint =
+ new AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfoCompat.ACTION_CLICK,
+ getResources().getString(R.string.accessibility_authenticate_hint));
+ private final AccessibilityNodeInfo.AccessibilityAction mAccessibilityEnterHint =
+ new AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfoCompat.ACTION_CLICK,
+ getResources().getString(R.string.accessibility_enter_hint));
+ public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(v, info);
+ removeAllActions(info);
+ if (mShowButton || mShowLockIcon) {
+ info.addAction(mAccessibilityAuthenticateHint);
+ } else if (mShowUnlockIcon) {
+ info.addAction(mAccessibilityEnterHint);
+ }
+ }
+
+ private void removeAllActions(AccessibilityNodeInfo info) {
+ info.removeAction(mAccessibilityAuthenticateHint);
+ info.removeAction(mAccessibilityEnterHint);
+ info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
+ mView.setLongClickable(false);
+ }
+ };
+
private boolean isLockScreen() {
return !mIsDozing
&& !mIsBouncerShowing
@@ -231,6 +278,17 @@
&& mStatusBarState == StatusBarState.KEYGUARD;
}
+ private void updateClickListener() {
+ if (mView != null) {
+ mView.setOnClickListener(v -> onAffordanceClick());
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ mView.setOnLongClickListener(null);
+ } else {
+ mView.setOnLongClickListener(v -> onAffordanceClick());
+ }
+ }
+ }
+
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println(" mShowBouncerButton: " + mShowButton);
@@ -298,4 +356,7 @@
updateVisibility();
}
};
+
+ private final AccessibilityManager.TouchExplorationStateChangeListener
+ mTouchExplorationStateChangeListener = enabled -> updateClickListener();
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
index d89dff5..5502a20 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
@@ -371,6 +371,7 @@
mAdapter.notifyDataSetChanged();
updateRadiusWith(mSizeType, mRadiusType, mTargets.size());
+ updateScrollModeWith(hasExceededMaxLayoutHeight());
setSystemGestureExclusion();
fadeOut();
@@ -614,6 +615,7 @@
updateColor();
updateStrokeWith(newConfig.uiMode, mAlignment);
updateLocationWith(mAlignment, mPercentageY);
+ updateScrollModeWith(hasExceededMaxLayoutHeight());
}
@VisibleForTesting
@@ -679,6 +681,12 @@
mListView.setLayoutParams(layoutParams);
}
+ private void updateScrollModeWith(boolean hasExceededMaxLayoutHeight) {
+ mListView.setOverScrollMode(hasExceededMaxLayoutHeight
+ ? OVER_SCROLL_ALWAYS
+ : OVER_SCROLL_NEVER);
+ }
+
private void updateColor() {
final int menuColorResId = R.color.accessibility_floating_menu_background;
getMenuGradientDrawable().setColor(getResources().getColor(menuColorResId));
@@ -726,6 +734,11 @@
layerDrawable.setLayerInset(INDEX_MENU_ITEM, left, 0, right, 0);
}
+ @VisibleForTesting
+ boolean hasExceededMaxLayoutHeight() {
+ return calculateActualLayoutHeight() > getMaxLayoutHeight();
+ }
+
@Alignment
private int calculateCurrentAlignment() {
return mCurrentLayoutParams.x >= ((MIN_WINDOW_X + getMaxWindowX()) / 2)
@@ -737,6 +750,10 @@
return mCurrentLayoutParams.y / (float) getMaxWindowY();
}
+ private int calculateActualLayoutHeight() {
+ return (mPadding + mIconHeight) * mTargets.size() + mPadding;
+ }
+
private @DimenRes int getRadiusResId(@SizeType int sizeType, int itemCount) {
return sizeType == SizeType.SMALL
? getSmallSizeResIdWith(itemCount)
@@ -760,13 +777,16 @@
return new Rect(0, 0, mScreenWidth - getWindowWidth(), mScreenHeight - getWindowHeight());
}
+ private int getMaxLayoutHeight() {
+ return mScreenHeight - mMargin * 2;
+ }
+
private int getLayoutWidth() {
return mPadding * 2 + mIconWidth;
}
private int getLayoutHeight() {
- return Math.min(mScreenHeight - mMargin * 2,
- (mPadding + mIconHeight) * mTargets.size() + mPadding);
+ return Math.min(getMaxLayoutHeight(), calculateActualLayoutHeight());
}
private int getWindowWidth() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 3d86034..179b077 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -20,6 +20,7 @@
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.Authenticators;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
@@ -39,6 +40,7 @@
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -57,6 +59,7 @@
import com.android.systemui.statusbar.CommandQueue;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
@@ -73,16 +76,13 @@
private static final String TAG = "AuthController";
private static final boolean DEBUG = true;
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
private final CommandQueue mCommandQueue;
private final StatusBarStateController mStatusBarStateController;
private final ActivityTaskManager mActivityTaskManager;
@Nullable private final FingerprintManager mFingerprintManager;
@Nullable private final FaceManager mFaceManager;
private final Provider<UdfpsController> mUdfpsControllerFactory;
-
- @Nullable private final List<FingerprintSensorPropertiesInternal> mFpProps;
- @Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
- @Nullable private final List<FingerprintSensorPropertiesInternal> mUdfpsProps;
@Nullable private final PointF mFaceAuthSensorLocation;
// TODO: These should just be saved from onSaveState
@@ -90,7 +90,6 @@
@VisibleForTesting
AuthDialog mCurrentDialog;
- private Handler mHandler = new Handler(Looper.getMainLooper());
private WindowManager mWindowManager;
@Nullable
private UdfpsController mUdfpsController;
@@ -98,6 +97,9 @@
TaskStackListener mTaskStackListener;
@VisibleForTesting
IBiometricSysuiReceiver mReceiver;
+ @Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
+ @Nullable private List<FingerprintSensorPropertiesInternal> mFpProps;
+ @Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps;
private class BiometricTaskStackListener extends TaskStackListener {
@Override
@@ -106,8 +108,31 @@
}
}
- @VisibleForTesting
- final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @NonNull
+ private final IFingerprintAuthenticatorsRegisteredCallback
+ mFingerprintAuthenticatorsRegisteredCallback =
+ new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
+ @Override public void onAllAuthenticatorsRegistered(
+ List<FingerprintSensorPropertiesInternal> sensors) {
+ if (DEBUG) {
+ Log.d(TAG, "onFingerprintProvidersAvailable | sensors: " + Arrays.toString(
+ sensors.toArray()));
+ }
+ mFpProps = sensors;
+ List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>();
+ for (FingerprintSensorPropertiesInternal props : mFpProps) {
+ if (props.isAnyUdfpsType()) {
+ udfpsProps.add(props);
+ }
+ }
+ mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null;
+ if (mUdfpsProps != null) {
+ mUdfpsController = mUdfpsControllerFactory.get();
+ }
+ }
+ };
+
+ @VisibleForTesting final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (mCurrentDialog != null
@@ -348,19 +373,8 @@
mFaceManager = faceManager;
mUdfpsControllerFactory = udfpsControllerFactory;
- mFpProps = mFingerprintManager != null ? mFingerprintManager.getSensorPropertiesInternal()
- : null;
mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null;
- List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>();
- if (mFpProps != null) {
- for (FingerprintSensorPropertiesInternal props : mFpProps) {
- if (props.isAnyUdfpsType()) {
- udfpsProps.add(props);
- }
- }
- }
- mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null;
int[] faceAuthLocation = context.getResources().getIntArray(
com.android.systemui.R.array.config_face_auth_props);
if (faceAuthLocation == null || faceAuthLocation.length < 2) {
@@ -383,9 +397,9 @@
mCommandQueue.addCallback(this);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()
- && mUdfpsProps != null) {
- mUdfpsController = mUdfpsControllerFactory.get();
+ if (mFingerprintManager != null) {
+ mFingerprintManager.addAuthenticatorsRegisteredCallback(
+ mFingerprintAuthenticatorsRegisteredCallback);
}
mTaskStackListener = new BiometricTaskStackListener();
@@ -527,7 +541,7 @@
return mFaceManager.hasEnrolledTemplates(userId);
}
- /**
+ /**
* Whether the passed userId has enrolled UDFPS.
*/
public boolean isUdfpsEnrolled(int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS b/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS
index 8765c9a..947466f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS
@@ -1,7 +1,3 @@
set noparent
-kchyn@google.com
-jaggies@google.com
-curtislb@google.com
-ilyamaty@google.com
-joshmccloskey@google.com
+include /services/core/java/com/android/server/biometrics/OWNERS
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index edb90c2..ee5fb31 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -28,7 +28,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.RectF;
@@ -55,6 +54,7 @@
import android.view.VelocityTracker;
import android.view.View;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -108,6 +108,7 @@
@NonNull private final Handler mMainHandler;
@NonNull private final FalsingManager mFalsingManager;
@NonNull private final PowerManager mPowerManager;
+ @NonNull private final AccessibilityManager mAccessibilityManager;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
// sensors, this, in addition to a lot of the code here, will be updated.
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
@@ -143,6 +144,8 @@
private final VibrationEffect mEffectClick = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
private final VibrationEffect mEffectHeavy =
VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
+ private final VibrationEffect mDoubleClick =
+ VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
private final Runnable mAcquiredVibration = new Runnable() {
@Override
public void run() {
@@ -274,6 +277,13 @@
private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) ->
onTouch(view, event, true);
+ @SuppressLint("ClickableViewAccessibility")
+ private final UdfpsView.OnHoverListener mOnHoverListener = (view, event) ->
+ onTouch(view, event, true);
+
+ private final AccessibilityManager.TouchExplorationStateChangeListener
+ mTouchExplorationStateChangeListener = enabled -> updateTouchListener();
+
/**
* @param x coordinate
* @param y coordinate
@@ -298,6 +308,7 @@
udfpsView.onTouchOutsideView();
break;
case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_HOVER_ENTER:
// To simplify the lifecycle of the velocity tracker, make sure it's never null
// after ACTION_DOWN, and always null after ACTION_CANCEL or ACTION_UP.
if (mVelocityTracker == null) {
@@ -320,6 +331,7 @@
break;
case MotionEvent.ACTION_MOVE:
+ case MotionEvent.ACTION_HOVER_MOVE:
final int idx = mActivePointerId == -1
? event.getPointerId(0)
: event.findPointerIndex(mActivePointerId);
@@ -386,6 +398,7 @@
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_HOVER_EXIT:
mActivePointerId = -1;
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
@@ -407,10 +420,9 @@
@Inject
public UdfpsController(@NonNull Context context,
- @Main Resources resources,
@NonNull LayoutInflater inflater,
@Nullable FingerprintManager fingerprintManager,
- WindowManager windowManager,
+ @NonNull WindowManager windowManager,
@NonNull StatusBarStateController statusBarStateController,
@Main DelayableExecutor fgExecutor,
@NonNull StatusBar statusBar,
@@ -419,7 +431,8 @@
@NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
@NonNull KeyguardViewMediator keyguardViewMediator,
@NonNull FalsingManager falsingManager,
- @NonNull PowerManager powerManager) {
+ @NonNull PowerManager powerManager,
+ @NonNull AccessibilityManager accessibilityManager) {
mContext = context;
// TODO (b/185124905): inject main handler and vibrator once done prototyping
mMainHandler = new Handler(Looper.getMainLooper());
@@ -438,6 +451,7 @@
mKeyguardViewMediator = keyguardViewMediator;
mFalsingManager = falsingManager;
mPowerManager = powerManager;
+ mAccessibilityManager = accessibilityManager;
mSensorProps = findFirstUdfps();
// At least one UDFPS sensor exists
@@ -575,7 +589,9 @@
mView.setAnimationViewController(animation);
mWindowManager.addView(mView, computeLayoutParams(animation));
- mView.setOnTouchListener(mOnTouchListener);
+ mAccessibilityManager.addTouchExplorationStateChangeListener(
+ mTouchExplorationStateChangeListener);
+ updateTouchListener();
} catch (RuntimeException e) {
Log.e(TAG, "showUdfpsOverlay | failed to add window", e);
}
@@ -648,7 +664,10 @@
onFingerUp();
mWindowManager.removeView(mView);
mView.setOnTouchListener(null);
+ mView.setOnHoverListener(null);
mView.setAnimationViewController(null);
+ mAccessibilityManager.removeTouchExplorationStateChangeListener(
+ mTouchExplorationStateChangeListener);
mView = null;
} else {
Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
@@ -750,8 +769,24 @@
return mEffectTextureTick;
case "tick":
return mEffectTick;
+ case "double_tap":
+ return mDoubleClick;
default:
return defaultEffect;
}
}
+
+ private void updateTouchListener() {
+ if (mView == null) {
+ return;
+ }
+
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ mView.setOnHoverListener(mOnHoverListener);
+ mView.setOnTouchListener(null);
+ } else {
+ mView.setOnHoverListener(null);
+ mView.setOnTouchListener(mOnTouchListener);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
index 01d5959..2808450 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -79,6 +79,7 @@
private final Collection<FalsingClassifier> mClassifiers;
private final List<FalsingBeliefListener> mFalsingBeliefListeners = new ArrayList<>();
+ private List<FalsingTapListener> mFalsingTapListeners = new ArrayList<>();
private final SessionListener mSessionListener = new SessionListener() {
@Override
@@ -196,31 +197,25 @@
public boolean isFalseTouch(@Classifier.InteractionType int interactionType) {
mPriorInteractionType = interactionType;
if (skipFalsing()) {
+ mPriorResults = getPassedResult(1);
+ logDebug("Skipped falsing");
return false;
}
- final boolean booleanResult;
+ final boolean[] localResult = {false};
+ mPriorResults = mClassifiers.stream().map(falsingClassifier -> {
+ FalsingClassifier.Result r = falsingClassifier.classifyGesture(
+ interactionType,
+ mHistoryTracker.falseBelief(),
+ mHistoryTracker.falseConfidence());
+ localResult[0] |= r.isFalse();
- if (!mTestHarness && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()) {
- final boolean[] localResult = {false};
- mPriorResults = mClassifiers.stream().map(falsingClassifier -> {
- FalsingClassifier.Result r = falsingClassifier.classifyGesture(
- interactionType,
- mHistoryTracker.falseBelief(),
- mHistoryTracker.falseConfidence());
- localResult[0] |= r.isFalse();
+ return r;
+ }).collect(Collectors.toList());
- return r;
- }).collect(Collectors.toList());
- booleanResult = localResult[0];
- } else {
- booleanResult = false;
- mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1));
- }
+ logDebug("False Gesture: " + localResult[0]);
- logDebug("False Gesture: " + booleanResult);
-
- return booleanResult;
+ return localResult[0];
}
@Override
@@ -235,6 +230,8 @@
@Override
public boolean isFalseTap(@Penalty int penalty) {
if (skipFalsing()) {
+ mPriorResults = getPassedResult(1);
+ logDebug("Skipped falsing");
return false;
}
@@ -263,7 +260,7 @@
if (!singleTapResult.isFalse()) {
if (mDataProvider.isJustUnlockedWithFace()) {
// Immediately pass if a face is detected.
- mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1));
+ mPriorResults = getPassedResult(1);
logDebug("False Single Tap: false (face detected)");
return false;
} else if (!isFalseDoubleTap()) {
@@ -277,9 +274,10 @@
FalsingClassifier.Result.falsed(
0, getClass().getSimpleName(), "bad history"));
logDebug("False Single Tap: true (bad history)");
+ mFalsingTapListeners.forEach(FalsingTapListener::onDoubleTapRequired);
return true;
} else {
- mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(0.1));
+ mPriorResults = getPassedResult(0.1);
logDebug("False Single Tap: false (default)");
return false;
}
@@ -294,6 +292,8 @@
@Override
public boolean isFalseDoubleTap() {
if (skipFalsing()) {
+ mPriorResults = getPassedResult(1);
+ logDebug("Skipped falsing");
return false;
}
@@ -307,7 +307,10 @@
}
private boolean skipFalsing() {
- return !mKeyguardStateController.isShowing();
+ return !mKeyguardStateController.isShowing()
+ || mTestHarness
+ || mDataProvider.isJustUnlockedWithFace()
+ || mDockManager.isDocked();
}
@Override
@@ -356,6 +359,16 @@
}
@Override
+ public void addTapListener(FalsingTapListener listener) {
+ mFalsingTapListeners.add(listener);
+ }
+
+ @Override
+ public void removeTapListener(FalsingTapListener listener) {
+ mFalsingTapListeners.remove(listener);
+ }
+
+ @Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
ipw.println("BRIGHTLINE FALSING MANAGER");
@@ -399,6 +412,10 @@
mHistoryTracker.removeBeliefListener(mBeliefListener);
}
+ private static Collection<FalsingClassifier.Result> getPassedResult(double confidence) {
+ return Collections.singleton(FalsingClassifier.Result.passed(confidence));
+ }
+
static void logDebug(String msg) {
logDebug(msg, null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
index 206af31..94e5c8a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -257,7 +257,7 @@
@Override
public void onTouchEvent(MotionEvent ev) {
- if (!mKeyguardStateController.isShowing()) {
+ if (!mKeyguardStateController.isShowing() || mStatusBarStateController.isDozing()) {
avoidGesture();
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
index e557773..e8445d4 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -146,4 +146,14 @@
public void removeFalsingBeliefListener(FalsingBeliefListener listener) {
mFalsingBeliefListeners.remove(listener);
}
+
+ @Override
+ public void addTapListener(FalsingTapListener falsingTapListener) {
+
+ }
+
+ @Override
+ public void removeTapListener(FalsingTapListener falsingTapListener) {
+
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 1723291..6b819fb 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -176,6 +176,16 @@
}
@Override
+ public void addTapListener(FalsingTapListener listener) {
+ mInternalFalsingManager.addTapListener(listener);
+ }
+
+ @Override
+ public void removeTapListener(FalsingTapListener listener) {
+ mInternalFalsingManager.removeTapListener(listener);
+ }
+
+ @Override
public void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
mInternalFalsingManager.onProximityEvent(proximityEvent);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index d8ade2b..4196465 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -376,8 +376,8 @@
case REASON_SENSOR_DOUBLE_TAP: return "doubletap";
case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress";
case PULSE_REASON_DOCKING: return "docking";
- case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakelockscreen";
- case REASON_SENSOR_WAKE_UP: return "wakeup";
+ case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "reach-wakelockscreen";
+ case REASON_SENSOR_WAKE_UP: return "presence-wakeup";
case REASON_SENSOR_TAP: return "tap";
case REASON_SENSOR_UDFPS_LONG_PRESS: return "udfps";
case REASON_SENSOR_QUICK_PICKUP: return "quickPickup";
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 5cea31b..39adabb 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -40,11 +40,9 @@
import androidx.annotation.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
-import com.android.internal.logging.nano.MetricsProto;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.plugins.SensorManagerPlugin;
@@ -491,10 +489,6 @@
mHandler.post(mWakeLock.wrap(() -> {
if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event));
if (mSensor != null && mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
- int subType = (int) event.values[0];
- MetricsLogger.action(
- mContext, MetricsProto.MetricsEvent.ACTION_AMBIENT_GESTURE,
- subType);
UI_EVENT_LOGGER.log(DozeSensorsUiEvent.ACTION_AMBIENT_GESTURE_PICKUP);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index ee55965..c45eb35 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -24,7 +24,6 @@
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.metrics.LogMaker;
import android.os.SystemClock;
import android.os.UserHandle;
import android.text.format.Formatter;
@@ -33,12 +32,8 @@
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.UiEventLoggerImpl;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
@@ -70,8 +65,6 @@
/** adb shell am broadcast -a com.android.systemui.doze.pulse com.android.systemui */
private static final String PULSE_ACTION = "com.android.systemui.doze.pulse";
- private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
-
/**
* Last value sent by the wake-display sensor.
* Assuming that the screen should start on.
@@ -99,12 +92,11 @@
private final BroadcastDispatcher mBroadcastDispatcher;
private final AuthController mAuthController;
private final DelayableExecutor mMainExecutor;
+ private final UiEventLogger mUiEventLogger;
private long mNotificationPulseTime;
private boolean mPulsePending;
- private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
-
/** see {@link #onProximityFar} prox for callback */
private boolean mWantProxSensor;
private boolean mWantTouchScreenSensors;
@@ -143,7 +135,10 @@
DOZING_UPDATE_AUTH_TRIGGERED(657),
@UiEvent(doc = "Dozing updated because quick pickup sensor woke up.")
- DOZING_UPDATE_QUICK_PICKUP(708);
+ DOZING_UPDATE_QUICK_PICKUP(708),
+
+ @UiEvent(doc = "Dozing updated - sensor wakeup timed out (from quick pickup or presence)")
+ DOZING_UPDATE_WAKE_TIMEOUT(794);
private final int mId;
@@ -182,7 +177,8 @@
ProximitySensor proximitySensor, ProximitySensor.ProximityCheck proxCheck,
DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher,
SecureSettings secureSettings, AuthController authController,
- @Main DelayableExecutor mainExecutor) {
+ @Main DelayableExecutor mainExecutor,
+ UiEventLogger uiEventLogger) {
mContext = context;
mDozeHost = dozeHost;
mConfig = config;
@@ -200,6 +196,7 @@
mBroadcastDispatcher = broadcastDispatcher;
mAuthController = authController;
mMainExecutor = mainExecutor;
+ mUiEventLogger = uiEventLogger;
}
@Override
@@ -328,11 +325,8 @@
private void gentleWakeUp(int reason) {
// Log screen wake up reason (lift/pickup, tap, double-tap)
- mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
- .setType(MetricsEvent.TYPE_UPDATE)
- .setSubtype(reason));
Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason))
- .ifPresent(UI_EVENT_LOGGER::log);
+ .ifPresent(mUiEventLogger::log);
if (mDozeParameters.getDisplayNeedsBlanking()) {
// Let's prepare the display to wake-up by drawing black.
// This will cover the hardware wake-up sequence, where the display
@@ -401,10 +395,9 @@
}
if (state == DozeMachine.State.DOZE) {
mMachine.requestState(DozeMachine.State.DOZE_AOD);
- // Logs AOD open due to sensor wake up.
- mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
- .setType(MetricsEvent.TYPE_OPEN)
- .setSubtype(reason));
+ // Log sensor triggered
+ Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason))
+ .ifPresent(mUiEventLogger::log);
if (isQuickPickup) {
// schedule runnable to go back to DOZE
@@ -427,10 +420,8 @@
return;
}
mMachine.requestState(DozeMachine.State.DOZE);
- // Logs AOD close due to sensor wake up.
- mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
- .setType(MetricsEvent.TYPE_CLOSE)
- .setSubtype(reason));
+ // log wake timeout
+ mUiEventLogger.log(DozingUpdateUiEvent.DOZING_UPDATE_WAKE_TIMEOUT);
}
}
}
@@ -563,10 +554,8 @@
}, !mDozeParameters.getProxCheckBeforePulse() || performedProxCheck, reason);
// Logs request pulse reason on AOD screen.
- mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
- .setType(MetricsEvent.TYPE_UPDATE).setSubtype(reason));
Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason))
- .ifPresent(UI_EVENT_LOGGER::log);
+ .ifPresent(mUiEventLogger::log);
}
private boolean canPulse() {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index e44e305..19edeb8 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -98,7 +98,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
-import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
@@ -117,6 +116,7 @@
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
+import com.android.systemui.scrim.ScrimDrawable;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.policy.ConfigurationController;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 767d7ab..411e0f0 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -30,11 +30,11 @@
import android.widget.TextView;
import com.android.internal.R;
-import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.GlobalActions;
+import com.android.systemui.scrim.ScrimDrawable;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.ScrimController;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 97803c1..666afed 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -70,7 +70,7 @@
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
*/
- private static boolean sEnableRemoteKeyguardAnimation =
+ static boolean sEnableRemoteKeyguardAnimation =
SystemProperties.getBoolean(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, false);
private final KeyguardViewMediator mKeyguardViewMediator;
@@ -138,6 +138,7 @@
@Override // Binder interface
public void onAnimationCancelled() {
+ mKeyguardViewMediator.cancelKeyguardExitAnimation();
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
new file mode 100644
index 0000000..411c328
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.Matrix
+import android.view.RemoteAnimationTarget
+import android.view.SyncRtSurfaceTransactionApplier
+import androidx.core.math.MathUtils
+import com.android.internal.R
+import com.android.keyguard.KeyguardViewController
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import dagger.Lazy
+import javax.inject.Inject
+
+/**
+ * Starting scale factor for the app/launcher surface behind the keyguard, when it's animating
+ * in during keyguard exit.
+ */
+const val SURFACE_BEHIND_START_SCALE_FACTOR = 0.95f
+
+/**
+ * How much to translate the surface behind the keyguard at the beginning of the exit animation,
+ * in terms of percentage of the surface's height.
+ */
+const val SURFACE_BEHIND_START_TRANSLATION_Y = 0.05f
+
+/**
+ * Y coordinate of the pivot point for the scale effect on the surface behind the keyguard. This
+ * is expressed as percentage of the surface's height, so 0.66f means the surface will scale up
+ * from the point at (width / 2, height * 0.66).
+ */
+const val SURFACE_BEHIND_SCALE_PIVOT_Y = 0.66f
+
+/**
+ * Dismiss amount at which to fade in the surface behind the keyguard. The surface will then animate
+ * along with the dismiss amount until [DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD] is reached.
+ *
+ * The dismiss amount is the inverse of the notification panel expansion, which decreases as the
+ * lock screen is swiped away.
+ */
+const val DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD = 0.1f
+
+/**
+ * Dismiss amount at which to complete the keyguard exit animation and hide the keyguard.
+ *
+ * The dismiss amount is the inverse of the notification panel expansion, which decreases as the
+ * lock screen is swiped away.
+ */
+const val DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD = 0.3f
+
+/**
+ * Initiates, controls, and ends the keyguard unlock animation.
+ *
+ * The unlock animation transitions between the keyguard (lock screen) and the app/launcher surface
+ * behind the keyguard. If the user is swiping away the keyguard, this controller will decide when
+ * to animate in the surface, and synchronize its appearance with the swipe gesture. If the keyguard
+ * is animating away via a canned animation (due to biometric unlock, tapping a notification, etc.)
+ * this controller will play a canned animation on the surface as well.
+ *
+ * The surface behind the keyguard is manipulated via a RemoteAnimation passed to
+ * [notifyStartKeyguardExitAnimation] by [KeyguardViewMediator].
+ */
+@SysUISingleton
+class KeyguardUnlockAnimationController @Inject constructor(
+ context: Context,
+ private val keyguardStateController: KeyguardStateController,
+ private val keyguardViewMediator: Lazy<KeyguardViewMediator>,
+ private val keyguardViewController: KeyguardViewController
+) : KeyguardStateController.Callback {
+
+ /**
+ * Information used to start, run, and finish a RemoteAnimation on the app or launcher surface
+ * behind the keyguard.
+ *
+ * If we're swiping to unlock, the "animation" is controlled via the gesture, tied to the
+ * dismiss amounts received in [onKeyguardDismissAmountChanged]. It does not have a fixed
+ * duration, and it ends when the gesture reaches a certain threshold or is cancelled.
+ *
+ * If we're unlocking via biometrics, PIN entry, or from clicking a notification, a canned
+ * animation is started in [notifyStartKeyguardExitAnimation].
+ */
+ private var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null
+ private var surfaceBehindRemoteAnimationTarget: RemoteAnimationTarget? = null
+ private var surfaceBehindRemoteAnimationStartTime: Long = 0
+
+ /**
+ * Alpha value applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the
+ * app/launcher behind the keyguard.
+ *
+ * If we're doing a swipe gesture, we fade in the surface when the swipe passes a certain
+ * threshold. If we're doing a canned animation, it'll be faded in while a translate/scale
+ * animation plays.
+ */
+ private var surfaceBehindAlpha = 1f
+ private var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f)
+
+ /**
+ * Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the
+ * app/launcher behind the keyguard.
+ *
+ * This is used during the unlock animation/swipe gesture to scale and translate the surface.
+ */
+ private val surfaceBehindMatrix = Matrix()
+
+ /**
+ * Animator that animates in the surface behind the keyguard. This is used to play a canned
+ * animation on the surface, if we're not doing a swipe gesture.
+ */
+ private val surfaceBehindEntryAnimator = ValueAnimator.ofFloat(0f, 1f)
+
+ /** Rounded corner radius to apply to the surface behind the keyguard. */
+ private var roundedCornerRadius = 0f
+
+ init {
+ surfaceBehindAlphaAnimator.duration = 150
+ surfaceBehindAlphaAnimator.interpolator = Interpolators.ALPHA_IN
+ surfaceBehindAlphaAnimator.addUpdateListener { valueAnimator: ValueAnimator ->
+ surfaceBehindAlpha = valueAnimator.animatedValue as Float
+ updateSurfaceBehindAppearAmount()
+ }
+ surfaceBehindAlphaAnimator.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ // If the surface alpha is 0f, it's no longer visible so we can safely be done with
+ // the animation.
+ if (surfaceBehindAlpha == 0f) {
+ keyguardViewMediator.get().finishSurfaceBehindRemoteAnimation()
+ }
+ }
+ })
+
+ surfaceBehindEntryAnimator.duration = 450
+ surfaceBehindEntryAnimator.interpolator = Interpolators.DECELERATE_QUINT
+ surfaceBehindEntryAnimator.addUpdateListener { valueAnimator: ValueAnimator ->
+ surfaceBehindAlpha = valueAnimator.animatedValue as Float
+ setSurfaceBehindAppearAmount(valueAnimator.animatedValue as Float)
+ }
+ surfaceBehindEntryAnimator.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished()
+ }
+ })
+
+ // Listen for changes in the dismiss amount.
+ keyguardStateController.addCallback(this)
+
+ roundedCornerRadius =
+ context.resources.getDimensionPixelSize(R.dimen.rounded_corner_radius).toFloat()
+ }
+
+ /**
+ * Called from [KeyguardViewMediator] to tell us that the RemoteAnimation on the surface behind
+ * the keyguard has started successfully. We can use these parameters to directly manipulate the
+ * surface for the unlock gesture/animation.
+ *
+ * When we're done with it, we'll call [KeyguardViewMediator.finishSurfaceBehindRemoteAnimation]
+ * to end the RemoteAnimation.
+ *
+ * [requestedShowSurfaceBehindKeyguard] denotes whether the exit animation started because of a
+ * call to [KeyguardViewMediator.showSurfaceBehindKeyguard], as happens during a swipe gesture,
+ * as opposed to the keyguard hiding.
+ */
+ fun notifyStartKeyguardExitAnimation(
+ target: RemoteAnimationTarget,
+ startTime: Long,
+ requestedShowSurfaceBehindKeyguard: Boolean
+ ) {
+
+ if (surfaceTransactionApplier == null) {
+ surfaceTransactionApplier = SyncRtSurfaceTransactionApplier(
+ keyguardViewController.viewRootImpl.view)
+ }
+
+ surfaceBehindRemoteAnimationTarget = target
+ surfaceBehindRemoteAnimationStartTime = startTime
+
+ // If the surface behind wasn't made visible during a swipe, we'll do a canned animation
+ // to animate it in. Otherwise, the swipe touch events will continue animating it.
+ if (!requestedShowSurfaceBehindKeyguard) {
+ keyguardViewController.hide(startTime, 350)
+ surfaceBehindEntryAnimator.start()
+ }
+ }
+
+ fun notifyCancelKeyguardExitAnimation() {
+ surfaceBehindRemoteAnimationTarget = null
+ }
+
+ fun notifyFinishedKeyguardExitAnimation() {
+ surfaceBehindRemoteAnimationTarget = null
+ }
+
+ fun hideKeyguardViewAfterRemoteAnimation() {
+ keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 350)
+ }
+
+ /**
+ * Scales in and translates up the surface behind the keyguard. This is used during unlock
+ * animations and swipe gestures to animate the surface's entry (and exit, if the swipe is
+ * cancelled).
+ */
+ private fun setSurfaceBehindAppearAmount(amount: Float) {
+ if (surfaceBehindRemoteAnimationTarget == null) {
+ return
+ }
+
+ val surfaceHeight: Int = surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.height()
+ val scaleFactor = (SURFACE_BEHIND_START_SCALE_FACTOR +
+ (1f - SURFACE_BEHIND_START_SCALE_FACTOR) *
+ MathUtils.clamp(amount, 0f, 1f))
+
+ // Scale up from a point at the center-bottom of the surface.
+ surfaceBehindMatrix.setScale(
+ scaleFactor,
+ scaleFactor,
+ surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.width() / 2f,
+ surfaceHeight * SURFACE_BEHIND_SCALE_PIVOT_Y)
+
+ // Translate up from the bottom.
+ surfaceBehindMatrix.postTranslate(0f,
+ surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount))
+
+ // If we're snapping the keyguard back, immediately begin fading it out.
+ val animationAlpha =
+ if (keyguardStateController.isSnappingKeyguardBackAfterSwipe) amount
+ else surfaceBehindAlpha
+
+ val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
+ surfaceBehindRemoteAnimationTarget!!.leash)
+ .withMatrix(surfaceBehindMatrix)
+ .withCornerRadius(roundedCornerRadius)
+ .withAlpha(animationAlpha)
+ .build()
+ surfaceTransactionApplier!!.scheduleApply(params)
+ }
+
+ /**
+ * Sets the appearance amount of the surface behind the keyguard, according to the current
+ * keyguard dismiss amount and the method of dismissal.
+ */
+ private fun updateSurfaceBehindAppearAmount() {
+ if (surfaceBehindRemoteAnimationTarget == null) {
+ return
+ }
+
+ // For fling animations, we want to animate the surface in over the full distance. If we're
+ // dismissing the keyguard via a swipe gesture (or cancelling the swipe gesture), we want to
+ // bring in the surface behind over a relatively short swipe distance (~15%), to keep the
+ // interaction tight.
+ if (keyguardStateController.isFlingingToDismissKeyguard) {
+ setSurfaceBehindAppearAmount(keyguardStateController.dismissAmount)
+ } else if (keyguardStateController.isDismissingFromSwipe ||
+ keyguardStateController.isSnappingKeyguardBackAfterSwipe) {
+ val totalSwipeDistanceToDismiss =
+ (DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD - DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD)
+ val swipedDistanceSoFar: Float =
+ keyguardStateController.dismissAmount - DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD
+ val progress = swipedDistanceSoFar / totalSwipeDistanceToDismiss
+ setSurfaceBehindAppearAmount(progress)
+ }
+ }
+
+ override fun onKeyguardDismissAmountChanged() {
+ if (!KeyguardService.sEnableRemoteKeyguardAnimation) {
+ return
+ }
+
+ val dismissAmount = keyguardStateController.dismissAmount
+
+ // Hide the keyguard if we're fully dismissed, or if we're swiping to dismiss and have
+ // crossed the threshold to finish the dismissal.
+ val reachedHideKeyguardThreshold = (dismissAmount >= 1f ||
+ (keyguardStateController.isDismissingFromSwipe &&
+ // Don't hide if we're flinging during a swipe, since we need to finish
+ // animating it out. This will be called again after the fling ends.
+ !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
+ dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD))
+
+ if (dismissAmount >= DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
+ !keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
+ // We passed the threshold, and we're not yet showing the surface behind the keyguard.
+ // Animate it in.
+ keyguardViewMediator.get().showSurfaceBehindKeyguard()
+ fadeInSurfaceBehind()
+ } else if (dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
+ keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
+ // We're no longer past the threshold but we are showing the surface. Animate it out.
+ keyguardViewMediator.get().hideSurfaceBehindKeyguard()
+ fadeOutSurfaceBehind()
+ } else if (keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe &&
+ reachedHideKeyguardThreshold) {
+ keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished()
+ }
+
+ if (keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() ||
+ keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) {
+ updateSurfaceBehindAppearAmount()
+ }
+ }
+
+ private fun fadeInSurfaceBehind() {
+ surfaceBehindAlphaAnimator.cancel()
+ surfaceBehindAlphaAnimator.start()
+ }
+
+ private fun fadeOutSurfaceBehind() {
+ surfaceBehindAlphaAnimator.cancel()
+ surfaceBehindAlphaAnimator.reverse()
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 70459df..48f9a58 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
@@ -72,7 +73,6 @@
import android.view.IRemoteAnimationFinishedCallback;
import android.view.RemoteAnimationTarget;
import android.view.SyncRtSurfaceTransactionApplier;
-import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -109,6 +109,7 @@
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.DeviceConfigProxy;
import java.io.FileDescriptor;
@@ -195,6 +196,7 @@
private static final int NOTIFY_SCREEN_TURNED_OFF = 16;
private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 17;
private static final int SYSTEM_READY = 18;
+ private static final int CANCEL_KEYGUARD_EXIT_ANIM = 19;
/**
* The default amount of time we stay awake (used for all key input)
@@ -350,7 +352,6 @@
private int mUnlockSoundId;
private int mTrustedSoundId;
private int mLockSoundStreamId;
-
/**
* The animation used for hiding keyguard. This is used to fetch the animation timings if
* WindowManager is not providing us with them.
@@ -400,6 +401,29 @@
private IKeyguardDrawnCallback mDrawnCallback;
private CharSequence mCustomMessage;
+ /**
+ * Whether the RemoteAnimation on the app/launcher surface behind the keyguard is 'running'.
+ * Note that this does not necessarily mean the surface is currently in motion - we may be
+ * 'animating' it along with the user's finger during a swipe to unlock gesture, a gesture that
+ * can be paused or reversed.
+ */
+ private boolean mSurfaceBehindRemoteAnimationRunning;
+
+ /**
+ * Whether we've asked to make the app/launcher surface behind the keyguard visible, via a call
+ * to {@link android.app.IActivityTaskManager#keyguardGoingAway(int)}.
+ *
+ * Since that's an IPC, this doesn't necessarily mean the remote animation has started yet.
+ * {@link #mSurfaceBehindRemoteAnimationRunning} will be true if the call completed and the
+ * animation is now running.
+ */
+ private boolean mSurfaceBehindRemoteAnimationRequested = false;
+
+ /**
+ * Callback to run to end the RemoteAnimation on the app/launcher surface behind the keyguard.
+ */
+ private IRemoteAnimationFinishedCallback mSurfaceBehindRemoteAnimationFinishedCallback;
+
private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
new DeviceConfig.OnPropertiesChangedListener() {
@Override
@@ -735,6 +759,9 @@
private DeviceConfigProxy mDeviceConfig;
private DozeParameters mDozeParameters;
+ private final KeyguardStateController mKeyguardStateController;
+ private final Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy;
+
/**
* Injected constructor. See {@link KeyguardModule}.
*/
@@ -752,7 +779,9 @@
NavigationModeController navigationModeController,
KeyguardDisplayManager keyguardDisplayManager,
DozeParameters dozeParameters,
- StatusBarStateController statusBarStateController) {
+ StatusBarStateController statusBarStateController,
+ KeyguardStateController keyguardStateController,
+ Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationControllerLazy) {
super(context);
mFalsingCollector = falsingCollector;
mLockPatternUtils = lockPatternUtils;
@@ -780,6 +809,9 @@
}));
mDozeParameters = dozeParameters;
statusBarStateController.addCallback(this);
+
+ mKeyguardStateController = keyguardStateController;
+ mKeyguardUnlockAnimationControllerLazy = keyguardUnlockAnimationControllerLazy;
}
public void userActivity() {
@@ -1732,6 +1764,12 @@
mFalsingCollector.onSuccessfulUnlock();
Trace.endSection();
break;
+ case CANCEL_KEYGUARD_EXIT_ANIM:
+ Trace.beginSection(
+ "KeyguardViewMediator#handleMessage CANCEL_KEYGUARD_EXIT_ANIM");
+ handleCancelKeyguardExitAnimation();
+ Trace.endSection();
+ break;
case KEYGUARD_DONE_PENDING_TIMEOUT:
Trace.beginSection("KeyguardViewMediator#handleMessage"
+ " KEYGUARD_DONE_PENDING_TIMEOUT");
@@ -1943,7 +1981,8 @@
int flags = 0;
if (mKeyguardViewControllerLazy.get().shouldDisableWindowAnimationsForUnlock()
- || (mWakeAndUnlocking && !mPulsing)) {
+ || (mWakeAndUnlocking && !mPulsing)
+ || isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) {
flags |= WindowManagerPolicyConstants
.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
}
@@ -1952,7 +1991,7 @@
flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
}
if (mKeyguardViewControllerLazy.get().isUnlockWithWallpaper()) {
- flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
+ flags |= KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
}
if (mKeyguardViewControllerLazy.get().shouldSubtleWindowAnimationsForUnlock()) {
flags |= WindowManagerPolicyConstants
@@ -2033,8 +2072,13 @@
+ " fadeoutDuration=" + fadeoutDuration);
synchronized (KeyguardViewMediator.this) {
- if (!mHiding) {
- // Tell ActivityManager that we canceled the keyguardExitAnimation.
+ // Tell ActivityManager that we canceled the keyguard animation if
+ // handleStartKeyguardExitAnimation was called but we're not hiding the keyguard, unless
+ // we're animating the surface behind the keyguard and will be hiding the keyguard
+ // shortly.
+ if (!mHiding
+ && !mSurfaceBehindRemoteAnimationRequested
+ && !mKeyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture()) {
setShowingLocked(mShowing, true /* force */);
return;
}
@@ -2056,61 +2100,184 @@
playSounds(false);
}
- setShowingLocked(false);
- mWakeAndUnlocking = false;
- mDismissCallbackRegistry.notifyDismissSucceeded();
- mKeyguardViewControllerLazy.get().hide(startTime, fadeoutDuration);
+ if (KeyguardService.sEnableRemoteKeyguardAnimation) {
+ mSurfaceBehindRemoteAnimationFinishedCallback = finishedCallback;
+ mSurfaceBehindRemoteAnimationRunning = true;
- // TODO(bc-animation): When remote animation is enabled for keyguard exit animation,
- // apps, wallpapers and finishedCallback are set to non-null. nonApps is not yet
- // supported, so it's always null.
- mContext.getMainExecutor().execute(() -> {
- if (finishedCallback == null) {
+ if (apps != null && apps.length > 0) {
+ // Pass the surface and metadata to the unlock animation controller.
+ mKeyguardUnlockAnimationControllerLazy.get().notifyStartKeyguardExitAnimation(
+ apps[0], startTime, mSurfaceBehindRemoteAnimationRequested);
+ } else {
+ // We weren't given any surfaces to animate, so just finish.
+ onKeyguardExitRemoteAnimationFinished();
return;
}
+ } else {
+ setShowingLocked(false);
+ mWakeAndUnlocking = false;
+ mDismissCallbackRegistry.notifyDismissSucceeded();
+ mKeyguardViewControllerLazy.get().hide(startTime, fadeoutDuration);
- // TODO(bc-unlock): Sample animation, just to apply alpha animation on the app.
- final SyncRtSurfaceTransactionApplier applier = new SyncRtSurfaceTransactionApplier(
- mKeyguardViewControllerLazy.get().getViewRootImpl().getView());
- final RemoteAnimationTarget primary = apps[0];
- ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
- anim.setDuration(400 /* duration */);
- anim.setInterpolator(Interpolators.LINEAR);
- anim.addUpdateListener((ValueAnimator animation) -> {
- SurfaceParams params = new SurfaceParams.Builder(primary.leash)
- .withAlpha(animation.getAnimatedFraction())
- .build();
- applier.scheduleApply(params);
- });
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- try {
- finishedCallback.onAnimationFinished();
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException");
- }
+ // TODO(bc-animation): When remote animation is enabled for keyguard exit animation,
+ // apps, wallpapers and finishedCallback are set to non-null. nonApps is not yet
+ // supported, so it's always null.
+ mContext.getMainExecutor().execute(() -> {
+ if (finishedCallback == null) {
+ return;
}
- @Override
- public void onAnimationCancel(Animator animation) {
- try {
- finishedCallback.onAnimationFinished();
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException");
+ // TODO(bc-unlock): Sample animation, just to apply alpha animation on the app.
+ final SyncRtSurfaceTransactionApplier applier =
+ new SyncRtSurfaceTransactionApplier(
+ mKeyguardViewControllerLazy.get().getViewRootImpl().getView());
+ final RemoteAnimationTarget primary = apps[0];
+ ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+ anim.setDuration(400 /* duration */);
+ anim.setInterpolator(Interpolators.LINEAR);
+ anim.addUpdateListener((ValueAnimator animation) -> {
+ SyncRtSurfaceTransactionApplier.SurfaceParams params =
+ new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
+ primary.leash)
+ .withAlpha(animation.getAnimatedFraction())
+ .build();
+ applier.scheduleApply(params);
+ });
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ try {
+ finishedCallback.onAnimationFinished();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException");
+ }
}
- }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ try {
+ finishedCallback.onAnimationFinished();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException");
+ }
+ }
+ });
+ anim.start();
});
- anim.start();
- });
- resetKeyguardDonePendingLocked();
- mHideAnimationRun = false;
- adjustStatusBarLocked();
- sendUserPresentBroadcast();
+ resetKeyguardDonePendingLocked();
+ mHideAnimationRun = false;
+ adjustStatusBarLocked();
+ sendUserPresentBroadcast();
+ }
}
+
Trace.endSection();
}
+ /**
+ * Whether we're currently animating between the keyguard and the app/launcher surface behind
+ * it, or will be shortly (which happens if we started a fling to dismiss the keyguard).
+ */
+ public boolean isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe() {
+ return mSurfaceBehindRemoteAnimationRunning
+ || mKeyguardStateController.isFlingingToDismissKeyguard();
+ }
+
+ /**
+ * Called if the keyguard exit animation has been cancelled and we should return to the
+ * keyguard.
+ *
+ * This can happen due to the system cancelling the RemoteAnimation (due to a timeout), or the
+ * user cancelling the unlock swipe gesture.
+ */
+ private void handleCancelKeyguardExitAnimation() {
+ hideSurfaceBehindKeyguard();
+ mKeyguardUnlockAnimationControllerLazy.get().notifyCancelKeyguardExitAnimation();
+ }
+
+ /**
+ * Called when we're done running the keyguard exit animation.
+ *
+ * This will call {@link #mSurfaceBehindRemoteAnimationFinishedCallback} to let WM know that
+ * we're done with the RemoteAnimation, actually hide the keyguard, and clean up state related
+ * to the keyguard exit animation.
+ */
+ public void onKeyguardExitRemoteAnimationFinished() {
+ if (!mSurfaceBehindRemoteAnimationRunning && !mSurfaceBehindRemoteAnimationRequested) {
+ return;
+ }
+
+ // Block the panel from expanding, in case we were doing a swipe to dismiss gesture.
+ mKeyguardViewControllerLazy.get().blockPanelExpansionFromCurrentTouch();
+ final boolean wasShowing = mShowing;
+ setShowingLocked(false);
+
+ mWakeAndUnlocking = false;
+ mDismissCallbackRegistry.notifyDismissSucceeded();
+
+ if (mKeyguardStateController.isDismissingFromSwipe() || !wasShowing) {
+ mKeyguardUnlockAnimationControllerLazy.get().hideKeyguardViewAfterRemoteAnimation();
+ }
+
+ finishSurfaceBehindRemoteAnimation();
+
+ resetKeyguardDonePendingLocked();
+ mHideAnimationRun = false;
+ adjustStatusBarLocked();
+ sendUserPresentBroadcast();
+ mSurfaceBehindRemoteAnimationRequested = false;
+ mKeyguardUnlockAnimationControllerLazy.get().notifyFinishedKeyguardExitAnimation();
+ }
+
+ /**
+ * Tells the ActivityTaskManager that the keyguard is planning to go away, so that it makes the
+ * surface behind the keyguard visible and calls {@link #handleStartKeyguardExitAnimation} with
+ * the parameters needed to animate the surface.
+ */
+ public void showSurfaceBehindKeyguard() {
+ mSurfaceBehindRemoteAnimationRequested = true;
+
+ try {
+ ActivityTaskManager.getService().keyguardGoingAway(
+ WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS
+ | WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER);
+ } catch (RemoteException e) {
+ mSurfaceBehindRemoteAnimationRequested = false;
+ e.printStackTrace();
+ }
+ }
+
+ /** Hides the surface behind the keyguard by re-showing the keyguard/activity lock screen. */
+ public void hideSurfaceBehindKeyguard() {
+ mSurfaceBehindRemoteAnimationRequested = false;
+
+ if (mShowing) {
+ setShowingLocked(true, true);
+ }
+ }
+
+ /**
+ * Whether we have requested to show the surface behind the keyguard, even if it's not yet
+ * visible due to IPC delay.
+ */
+ public boolean requestedShowSurfaceBehindKeyguard() {
+ return mSurfaceBehindRemoteAnimationRequested;
+ }
+
+ /** If it's running, finishes the RemoteAnimation on the surface behind the keyguard. */
+ public void finishSurfaceBehindRemoteAnimation() {
+ mSurfaceBehindRemoteAnimationRunning = false;
+
+ if (mSurfaceBehindRemoteAnimationFinishedCallback != null) {
+ try {
+ mSurfaceBehindRemoteAnimationFinishedCallback.onAnimationFinished();
+ mSurfaceBehindRemoteAnimationFinishedCallback = null;
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
private void adjustStatusBarLocked() {
adjustStatusBarLocked(false /* forceHideHomeRecentsButtons */,
false /* forceClearFlags */);
@@ -2346,6 +2513,19 @@
Trace.endSection();
}
+ /**
+ * Cancel the keyguard exit animation, usually because we were swiping to unlock and the swipe
+ * gesture was cancelled.
+ *
+ * This will re-show the keyguard and animate out the app/launcher surface behind the keyguard.
+ */
+ public void cancelKeyguardExitAnimation() {
+ Trace.beginSection("KeyguardViewMediator#cancelKeyguardExitAnimation");
+ Message msg = mHandler.obtainMessage(CANCEL_KEYGUARD_EXIT_ANIM);
+ mHandler.sendMessage(msg);
+ Trace.endSection();
+ }
+
public void onShortPowerPressedGoHome() {
// do nothing
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index a747edd..ecee1b5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -42,6 +42,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -49,6 +50,7 @@
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardLiftController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.settings.GlobalSettings;
@@ -92,7 +94,9 @@
NavigationModeController navigationModeController,
KeyguardDisplayManager keyguardDisplayManager,
DozeParameters dozeParameters,
- StatusBarStateController statusBarStateController) {
+ StatusBarStateController statusBarStateController,
+ KeyguardStateController keyguardStateController,
+ Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController) {
return new KeyguardViewMediator(
context,
falsingCollector,
@@ -109,7 +113,9 @@
navigationModeController,
keyguardDisplayManager,
dozeParameters,
- statusBarStateController
+ statusBarStateController,
+ keyguardStateController,
+ keyguardUnlockAnimationController
);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
index 6fb8650..2ea139e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
@@ -17,6 +17,7 @@
package com.android.systemui.media
import android.view.View
+import android.view.ViewGroup
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.media.dagger.MediaModule.KEYGUARD
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -29,8 +30,8 @@
import javax.inject.Named
/**
- * A class that controls the media notifications on the lock screen, handles its visibility and
- * is responsible for the embedding of he media experience.
+ * Controls the media notifications on the lock screen, handles its visibility and placement -
+ * switches media player positioning between split pane container vs single pane container
*/
@SysUISingleton
class KeyguardMediaController @Inject constructor(
@@ -43,46 +44,114 @@
init {
statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
override fun onStateChanged(newState: Int) {
- updateVisibility()
+ refreshMediaPosition()
+ }
+
+ override fun onDozingChanged(isDozing: Boolean) {
+ if (!isDozing) {
+ mediaHost.visible = true
+ refreshMediaPosition()
+ }
}
})
}
var visibilityChangedListener: ((Boolean) -> Unit)? = null
- var view: MediaHeaderView? = null
- private set
/**
- * Attach this controller to a media view, initializing its state
+ * single pane media container placed at the top of the notifications list
*/
- fun attach(mediaView: MediaHeaderView) {
- view = mediaView
+ var singlePaneContainer: MediaHeaderView? = null
+ private set
+ private var splitShadeContainer: ViewGroup? = null
+ private var useSplitShadeContainer: () -> Boolean = { false }
+
+ /**
+ * Attaches media container in single pane mode, situated at the top of the notifications list
+ */
+ fun attachSinglePaneContainer(mediaView: MediaHeaderView?) {
+ singlePaneContainer = mediaView
// First let's set the desired state that we want for this host
- mediaHost.addVisibilityChangeListener { updateVisibility() }
- mediaHost.expansion = 0.0f
+ mediaHost.expansion = MediaHostState.COLLAPSED
mediaHost.showsOnlyActiveMedia = true
mediaHost.falsingProtectionNeeded = true
// Let's now initialize this view, which also creates the host view for us.
mediaHost.init(MediaHierarchyManager.LOCATION_LOCKSCREEN)
- mediaView.setContentView(mediaHost.hostView)
-
- // Ensure the visibility is correct
- updateVisibility()
+ // Required to show it for the first time, afterwards visibility is managed automatically
+ mediaHost.visible = true
+ mediaHost.addVisibilityChangeListener { visible ->
+ refreshMediaPosition()
+ if (visible) {
+ mediaHost.hostView.layoutParams.apply {
+ height = ViewGroup.LayoutParams.WRAP_CONTENT
+ width = ViewGroup.LayoutParams.MATCH_PARENT
+ }
+ }
+ }
+ refreshMediaPosition()
}
- private fun updateVisibility() {
+ /**
+ * Attaches media container in split shade mode, situated to the left of notifications
+ */
+ fun attachSplitShadeContainer(container: ViewGroup, useContainer: () -> Boolean) {
+ splitShadeContainer = container
+ useSplitShadeContainer = useContainer
+ }
+
+ fun refreshMediaPosition() {
val keyguardOrUserSwitcher = (statusBarStateController.state == StatusBarState.KEYGUARD ||
statusBarStateController.state == StatusBarState.FULLSCREEN_USER_SWITCHER)
+ // mediaHost.visible required for proper animations handling
val shouldBeVisible = mediaHost.visible &&
!bypassController.bypassEnabled &&
keyguardOrUserSwitcher &&
notifLockscreenUserManager.shouldShowLockscreenNotifications()
- val previousVisibility = view?.visibility ?: View.GONE
- val newVisibility = if (shouldBeVisible) View.VISIBLE else View.GONE
+ if (shouldBeVisible) {
+ showMediaPlayer()
+ } else {
+ hideMediaPlayer()
+ }
+ }
+
+ private fun showMediaPlayer() {
+ if (useSplitShadeContainer()) {
+ showMediaPlayer(
+ activeContainer = splitShadeContainer,
+ inactiveContainer = singlePaneContainer)
+ } else {
+ showMediaPlayer(
+ activeContainer = singlePaneContainer,
+ inactiveContainer = splitShadeContainer)
+ }
+ }
+
+ private fun showMediaPlayer(activeContainer: ViewGroup?, inactiveContainer: ViewGroup?) {
+ if (inactiveContainer?.childCount == 1) {
+ inactiveContainer.removeAllViews()
+ }
+ // might be called a few times for the same view, no need to add hostView again
+ if (activeContainer?.childCount == 0) {
+ activeContainer.addView(mediaHost.hostView)
+ }
+ setVisibility(activeContainer, View.VISIBLE)
+ setVisibility(inactiveContainer, View.GONE)
+ }
+
+ private fun hideMediaPlayer() {
+ if (useSplitShadeContainer()) {
+ setVisibility(splitShadeContainer, View.GONE)
+ } else {
+ setVisibility(singlePaneContainer, View.GONE)
+ }
+ }
+
+ private fun setVisibility(view: ViewGroup?, newVisibility: Int) {
+ val previousVisibility = view?.visibility
view?.visibility = newVisibility
if (previousVisibility != newVisibility) {
- visibilityChangedListener?.invoke(shouldBeVisible)
+ visibilityChangedListener?.invoke(newVisibility == View.VISIBLE)
}
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 2ecd405..c3c617c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -319,7 +319,7 @@
val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
- newRecs.bindRecommendation(data, bgColor, { v -> removePlayer(key) })
+ newRecs.bindRecommendation(data, bgColor)
MediaPlayerData.addMediaPlayer(key, newRecs)
updatePlayerToState(newRecs, noAnimation = true)
reorderAllPlayers()
@@ -348,11 +348,11 @@
if (dismissMediaData) {
// Inform the media manager of a potentially late dismissal
- mediaManager.dismissMediaData(key, 0L)
+ mediaManager.dismissMediaData(key, 0L /* delaye */)
}
if (dismissRecommendation) {
// Inform the media manager of a potentially late dismissal
- mediaManager.dismissSmartspaceRecommendation()
+ mediaManager.dismissSmartspaceRecommendation(0L /* delay */)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 495461e..473db9f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -54,6 +54,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.util.animation.TransitionLayout;
@@ -241,6 +242,21 @@
TransitionLayout recommendations = vh.getRecommendations();
mMediaViewController.attach(recommendations, MediaViewController.TYPE.RECOMMENDATION);
+
+ mRecommendationViewHolder.getRecommendations().setOnLongClickListener(v -> {
+ if (!mMediaViewController.isGutsVisible()) {
+ mMediaViewController.openGuts();
+ return true;
+ } else {
+ return false;
+ }
+ });
+ mRecommendationViewHolder.getCancel().setOnClickListener(v -> {
+ closeGuts();
+ });
+ mRecommendationViewHolder.getSettings().setOnClickListener(v -> {
+ mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
+ });
}
/** Bind this player view based on the data given. */
@@ -460,10 +476,7 @@
}
/** Bind this recommendation view based on the data given. */
- public void bindRecommendation(
- @NonNull SmartspaceTarget target,
- @NonNull int backgroundColor,
- @Nullable View.OnClickListener callback) {
+ public void bindRecommendation(@NonNull SmartspaceTarget target, @NonNull int backgroundColor) {
if (mRecommendationViewHolder == null) {
return;
}
@@ -519,7 +532,13 @@
mediaCoverImageView.setImageIcon(recommendation.getIcon());
// Set up the click listener if applicable.
- setSmartspaceOnClickListener(mediaCoverImageView, recommendation, callback);
+ setSmartspaceRecItemOnClickListener(
+ mediaCoverImageView,
+ recommendation,
+ target.getSmartspaceTargetId(),
+ view -> mMediaDataManagerLazy
+ .get()
+ .dismissSmartspaceRecommendation(0L /* delay */));
setVisibleAndAlpha(expandedSet, mediaCoverItemsResIds.get(i), true);
setVisibleAndAlpha(expandedSet, mediaLogoItemsResIds.get(i), true);
@@ -527,6 +546,16 @@
setVisibleAndAlpha(collapsedSet, mediaLogoItemsResIds.get(i), true);
}
+ // Set up long press to show guts setting panel.
+ mRecommendationViewHolder.getDismiss().setOnClickListener(v -> {
+ closeGuts();
+ mKeyguardDismissUtil.executeWhenUnlocked(() -> {
+ mMediaDataManagerLazy.get().dismissSmartspaceRecommendation(
+ MediaViewController.GUTS_ANIMATION_DURATION + 100L);
+ return true;
+ }, true /* requiresShadeOpen */);
+ });
+
mController = null;
mMediaViewController.refreshState();
}
@@ -611,9 +640,10 @@
set.setAlpha(actionId, visible ? 1.0f : 0.0f);
}
- private void setSmartspaceOnClickListener(
+ private void setSmartspaceRecItemOnClickListener(
@NonNull View view,
@NonNull SmartspaceAction action,
+ @NonNull String targetId,
@Nullable View.OnClickListener callback) {
if (view == null || action == null || action.getIntent() == null) {
Log.e(TAG, "No tap action can be set up");
@@ -621,6 +651,16 @@
}
view.setOnClickListener(v -> {
+ // When media recommendation card is shown, there could be only one card.
+ SysUiStatsLog.write(SysUiStatsLog.SMARTSPACE_CARD_REPORTED,
+ 760, // SMARTSPACE_CARD_CLICK
+ targetId.hashCode(),
+ SysUiStatsLog
+ .SMART_SPACE_CARD_REPORTED__CARD_TYPE__HEADPHONE_MEDIA_RECOMMENDATIONS,
+ getSurfaceForSmartspaceLogging(mMediaViewController.getCurrentEndLocation()),
+ /* rank */ 1,
+ /* cardinality */ 1);
+
mActivityStarter.postStartActivityDismissingKeyguard(
action.getIntent(),
0 /* delay */,
@@ -630,4 +670,14 @@
}
});
}
+
+ private int getSurfaceForSmartspaceLogging(int currentEndLocation) {
+ if (currentEndLocation == MediaHierarchyManager.LOCATION_QQS
+ || currentEndLocation == MediaHierarchyManager.LOCATION_QS) {
+ return SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE;
+ } else if (currentEndLocation == MediaHierarchyManager.LOCATION_LOCKSCREEN) {
+ return SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN;
+ }
+ return SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DEFAULT_SURFACE;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index 0ed96ee..6ef29d6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -104,7 +104,12 @@
/**
* Set from the notification and used as fallback when PlaybackState cannot be determined
*/
- val isClearable: Boolean = true
+ val isClearable: Boolean = true,
+
+ /**
+ * Timestamp when this player was last active.
+ */
+ var lastActive: Long = 0L
)
/** State of a media action. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
index a274eab..2bd7729 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
@@ -17,6 +17,7 @@
package com.android.systemui.media
import android.app.smartspace.SmartspaceTarget
+import android.os.SystemProperties
import android.util.Log
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -24,14 +25,23 @@
import com.android.systemui.settings.CurrentUserTracker
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import java.util.concurrent.Executor
+import java.util.concurrent.TimeUnit
import javax.inject.Inject
private const val TAG = "MediaDataFilter"
private const val DEBUG = true
/**
+ * Maximum age of a media control to re-activate on smartspace signal. If there is no media control
+ * available within this time window, smartspace recommendations will be shown instead.
+ */
+private val SMARTSPACE_MAX_AGE = SystemProperties
+ .getLong("debug.sysui.smartspace_max_age", TimeUnit.HOURS.toMillis(3))
+
+/**
* Filters data updates from [MediaDataCombineLatest] based on the current user ID, and handles user
- * switches (removing entries for the previous user, adding back entries for the current user)
+ * switches (removing entries for the previous user, adding back entries for the current user). Also
+ * filters out smartspace updates in favor of local recent media, when avaialble.
*
* This is added at the end of the pipeline since we may still need to handle callbacks from
* background users (e.g. timeouts).
@@ -52,6 +62,7 @@
// The filtered userEntries, which will be a subset of all userEntries in MediaDataManager
private val userEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
private var hasSmartspace: Boolean = false
+ private var reactivatedKey: String? = null
init {
userTracker = object : CurrentUserTracker(broadcastDispatcher) {
@@ -86,6 +97,30 @@
override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {
hasSmartspace = true
+
+ // Before forwarding the smartspace target, first check if we have recently inactive media
+ val now = System.currentTimeMillis()
+ val sorted = userEntries.toSortedMap(compareBy {
+ userEntries.get(it)?.lastActive ?: -1
+ })
+ if (sorted.size > 0) {
+ val lastActiveKey = sorted.lastKey() // most recently active
+ val timeSinceActive = sorted.get(lastActiveKey)?.let {
+ now - it.lastActive
+ } ?: Long.MAX_VALUE
+ if (timeSinceActive < SMARTSPACE_MAX_AGE) {
+ // Notify listeners to consider this media active
+ Log.d(TAG, "reactivating $lastActiveKey instead of smartspace")
+ reactivatedKey = lastActiveKey
+ val mediaData = sorted.get(lastActiveKey)!!.copy(active = true)
+ listeners.forEach {
+ it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData)
+ }
+ return
+ }
+ }
+
+ // If no recent media, continue with smartspace update
listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data) }
}
@@ -101,6 +136,21 @@
override fun onSmartspaceMediaDataRemoved(key: String) {
hasSmartspace = false
+
+ // First check if we had reactivated media instead of forwarding smartspace
+ reactivatedKey?.let {
+ val lastActiveKey = it
+ reactivatedKey = null
+ Log.d(TAG, "expiring reactivated key $lastActiveKey")
+ // Notify listeners to update with actual active value
+ userEntries.get(lastActiveKey)?.let { mediaData ->
+ listeners.forEach {
+ it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData)
+ }
+ }
+ return
+ }
+
listeners.forEach { it.onSmartspaceMediaDataRemoved(key) }
}
@@ -137,10 +187,11 @@
if (DEBUG) Log.d(TAG, "Media carousel swiped away")
val mediaKeys = userEntries.keys.toSet()
mediaKeys.forEach {
- mediaDataManager.setTimedOut(it, timedOut = true)
+ // Force updates to listeners, needed for re-activated card
+ mediaDataManager.setTimedOut(it, timedOut = true, forceUpdate = true)
}
if (hasSmartspace) {
- mediaDataManager.dismissSmartspaceRecommendation()
+ mediaDataManager.dismissSmartspaceRecommendation(0L /* delay */)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 5ba04a0..a070861 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -394,9 +394,9 @@
* This will make the player not active anymore, hiding it from QQS and Keyguard.
* @see MediaData.active
*/
- internal fun setTimedOut(token: String, timedOut: Boolean) {
+ internal fun setTimedOut(token: String, timedOut: Boolean, forceUpdate: Boolean = false) {
mediaEntries[token]?.let {
- if (it.active == !timedOut) {
+ if (it.active == !timedOut && !forceUpdate) {
return
}
it.active = !timedOut
@@ -429,12 +429,13 @@
* This will make the recommendation view to not be shown anymore during this headphone
* connection session.
*/
- fun dismissSmartspaceRecommendation() {
+ fun dismissSmartspaceRecommendation(delay: Long) {
Log.d(TAG, "Dismissing Smartspace media target")
// Do not set smartspaceMediaTarget to null. So the instance is preserved during the entire
// headphone connection, and will ONLY be set to null when headphones are disconnected.
smartspaceMediaTarget?.let {
- notifySmartspaceMediaDataRemoved(it.smartspaceTargetId)
+ foregroundExecutor.executeDelayed(
+ { notifySmartspaceMediaDataRemoved(it.smartspaceTargetId) }, delay)
}
}
@@ -470,12 +471,13 @@
}
val mediaAction = getResumeMediaAction(resumeAction)
+ val lastActive = System.currentTimeMillis()
foregroundExecutor.execute {
onMediaDataLoaded(packageName, null, MediaData(userId, true, bgColor, appName,
null, desc.subtitle, desc.title, artworkIcon, listOf(mediaAction), listOf(0),
packageName, token, appIntent, device = null, active = false,
resumeAction = resumeAction, resumption = true, notificationKey = packageName,
- hasCheckedForResume = true))
+ hasCheckedForResume = true, lastActive = lastActive))
}
}
@@ -586,9 +588,9 @@
}
val isLocalSession = mediaController.playbackInfo?.playbackType ==
- MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL ?: true
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL
val isPlaying = mediaController.playbackState?.let { isPlayingState(it.state) } ?: null
-
+ val lastActive = System.currentTimeMillis()
foregroundExecutor.execute {
val resumeAction: Runnable? = mediaEntries[key]?.resumeAction
val hasCheckedForResume = mediaEntries[key]?.hasCheckedForResume == true
@@ -598,7 +600,8 @@
actionsToShowCollapsed, sbn.packageName, token, notif.contentIntent, null,
active, resumeAction = resumeAction, isLocalSession = isLocalSession,
notificationKey = key, hasCheckedForResume = hasCheckedForResume,
- isPlaying = isPlaying, isClearable = sbn.isClearable()))
+ isPlaying = isPlaying, isClearable = sbn.isClearable(),
+ lastActive = lastActive))
}
}
@@ -724,7 +727,7 @@
Assert.isMainThread()
val removed = mediaEntries.remove(key)
if (useMediaResumption && removed?.resumeAction != null &&
- !isBlockedFromResume(removed.packageName)) {
+ !isBlockedFromResume(removed.packageName) && removed?.isLocalSession == true) {
Log.d(TAG, "Not removing $key because resumable")
// Move to resume key (aka package name) if that key doesn't already exist.
val resumeAction = getResumeMediaAction(removed.resumeAction!!)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
index 8c12a30..2347481 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
@@ -264,15 +264,20 @@
*/
interface MediaHostState {
+ companion object {
+ const val EXPANDED: Float = 1.0f
+ const val COLLAPSED: Float = 0.0f
+ }
+
/**
- * The last measurement input that this state was measured with. Infers with and height of
+ * The last measurement input that this state was measured with. Infers width and height of
* the players.
*/
var measurementInput: MeasurementInput?
/**
- * The expansion of the player, 0 for fully collapsed (up to 3 actions), 1 for fully expanded
- * (up to 5 actions.)
+ * The expansion of the player, [COLLAPSED] for fully collapsed (up to 3 actions),
+ * [EXPANDED] for fully expanded (up to 5 actions).
*/
var expansion: Float
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
index 80d1371..b0be576 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
@@ -173,7 +173,7 @@
mediaBrowser?.disconnect()
// If we don't have a resume action, check if we haven't already
if (data.resumeAction == null && !data.hasCheckedForResume &&
- !blockedApps.contains(data.packageName)) {
+ !blockedApps.contains(data.packageName) && data.isLocalSession) {
// TODO also check for a media button receiver intended for restarting (b/154127084)
Log.d(TAG, "Checking for service component for " + data.packageName)
val pm = context.packageManager
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
index ce72991..8bfe94b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
@@ -51,36 +51,53 @@
lateinit var timeoutCallback: (String, Boolean) -> Unit
override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
- if (mediaListeners.containsKey(key)) {
- return
+ var reusedListener: PlaybackStateListener? = null
+
+ // First check if we already have a listener
+ mediaListeners.get(key)?.let {
+ if (!it.destroyed) {
+ return
+ }
+
+ // If listener was destroyed previously, we'll need to re-register it
+ if (DEBUG) {
+ Log.d(TAG, "Reusing destroyed listener $key")
+ }
+ reusedListener = it
}
+
// Having an old key means that we're migrating from/to resumption. We should update
// the old listener to make sure that events will be dispatched to the new location.
val migrating = oldKey != null && key != oldKey
if (migrating) {
- val reusedListener = mediaListeners.remove(oldKey)
+ reusedListener = mediaListeners.remove(oldKey)
if (reusedListener != null) {
- val wasPlaying = reusedListener.playing ?: false
if (DEBUG) Log.d(TAG, "migrating key $oldKey to $key, for resumption")
- reusedListener.mediaData = data
- reusedListener.key = key
- mediaListeners[key] = reusedListener
- if (wasPlaying != reusedListener.playing) {
- // If a player becomes active because of a migration, we'll need to broadcast
- // its state. Doing it now would lead to reentrant callbacks, so let's wait
- // until we're done.
- mainExecutor.execute {
- if (mediaListeners[key]?.playing == true) {
- if (DEBUG) Log.d(TAG, "deliver delayed playback state for $key")
- timeoutCallback.invoke(key, false /* timedOut */)
- }
- }
- }
- return
} else {
Log.w(TAG, "Old key $oldKey for player $key doesn't exist. Continuing...")
}
}
+
+ reusedListener?.let {
+ val wasPlaying = it.playing ?: false
+ if (DEBUG) Log.d(TAG, "updating listener for $key, was playing? $wasPlaying")
+ it.mediaData = data
+ it.key = key
+ mediaListeners[key] = it
+ if (wasPlaying != it.playing) {
+ // If a player becomes active because of a migration, we'll need to broadcast
+ // its state. Doing it now would lead to reentrant callbacks, so let's wait
+ // until we're done.
+ mainExecutor.execute {
+ if (mediaListeners[key]?.playing == true) {
+ if (DEBUG) Log.d(TAG, "deliver delayed playback state for $key")
+ timeoutCallback.invoke(key, false /* timedOut */)
+ }
+ }
+ }
+ return
+ }
+
mediaListeners[key] = PlaybackStateListener(key, data)
}
@@ -99,9 +116,11 @@
var timedOut = false
var playing: Boolean? = null
+ var destroyed = false
var mediaData: MediaData = data
set(value) {
+ destroyed = false
mediaController?.unregisterCallback(this)
field = value
mediaController = if (field.token != null) {
@@ -126,15 +145,25 @@
fun destroy() {
mediaController?.unregisterCallback(this)
cancellation?.run()
+ destroyed = true
}
override fun onPlaybackStateChanged(state: PlaybackState?) {
processState(state, dispatchEvents = true)
}
+ override fun onSessionDestroyed() {
+ // If the session is destroyed, the controller is no longer valid, and we will need to
+ // recreate it if this key is updated later
+ if (DEBUG) {
+ Log.d(TAG, "Session destroyed for $key")
+ }
+ destroy()
+ }
+
private fun processState(state: PlaybackState?, dispatchEvents: Boolean) {
if (DEBUG) {
- Log.v(TAG, "processState: $state")
+ Log.v(TAG, "processState $key: $state")
}
val isPlaying = state != null && isPlayingState(state.state)
@@ -173,8 +202,7 @@
private fun expireMediaTimeout(mediaKey: String, reason: String) {
cancellation?.apply {
if (DEBUG) {
- Log.v(TAG,
- "media timeout cancelled for $mediaKey, reason: $reason")
+ Log.v(TAG, "media timeout cancelled for $mediaKey, reason: $reason")
}
run()
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index 7cfe4c4..f78556f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -70,11 +70,10 @@
* finished
*/
@MediaLocation
- private var currentEndLocation: Int = -1
+ var currentEndLocation: Int = -1
/**
- * The ending location of the view where it ends when all animations and transitions have
- * finished
+ * The starting location of the view where it starts for all animations and transitions
*/
@MediaLocation
private var currentStartLocation: Int = -1
@@ -253,16 +252,30 @@
* [TransitionViewState].
*/
private fun setGutsViewState(viewState: TransitionViewState) {
- PlayerViewHolder.controlsIds.forEach { id ->
- viewState.widgetStates.get(id)?.let { state ->
- // Make sure to use the unmodified state if guts are not visible
- state.alpha = if (isGutsVisible) 0f else state.alpha
- state.gone = if (isGutsVisible) true else state.gone
+ if (type == TYPE.PLAYER) {
+ PlayerViewHolder.controlsIds.forEach { id ->
+ viewState.widgetStates.get(id)?.let { state ->
+ // Make sure to use the unmodified state if guts are not visible.
+ state.alpha = if (isGutsVisible) 0f else state.alpha
+ state.gone = if (isGutsVisible) true else state.gone
+ }
}
- }
- PlayerViewHolder.gutsIds.forEach { id ->
- viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
- viewState.widgetStates.get(id)?.gone = !isGutsVisible
+ PlayerViewHolder.gutsIds.forEach { id ->
+ viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
+ viewState.widgetStates.get(id)?.gone = !isGutsVisible
+ }
+ } else {
+ RecommendationViewHolder.controlsIds.forEach { id ->
+ viewState.widgetStates.get(id)?.let { state ->
+ // Make sure to use the unmodified state if guts are not visible.
+ state.alpha = if (isGutsVisible) 0f else state.alpha
+ state.gone = if (isGutsVisible) true else state.gone
+ }
+ }
+ RecommendationViewHolder.gutsIds.forEach { id ->
+ viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
+ viewState.widgetStates.get(id)?.gone = !isGutsVisible
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt
index ac201a8..19c83bc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt
@@ -20,6 +20,7 @@
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
+import android.widget.TextView
import androidx.annotation.IntegerRes
import com.android.systemui.R
import com.android.systemui.util.animation.TransitionLayout
@@ -28,6 +29,8 @@
class RecommendationViewHolder private constructor(itemView: View) {
val recommendations = itemView as TransitionLayout
+
+ // Recommendation screen
val mediaCoverItems = listOf<ImageView>(
itemView.requireViewById(R.id.media_cover1),
itemView.requireViewById(R.id.media_cover2),
@@ -49,16 +52,27 @@
R.id.media_logo3,
R.id.media_logo4)
+ // Settings/Guts screen
+ val cancel = itemView.requireViewById<View>(R.id.cancel)
+ val dismiss = itemView.requireViewById<ViewGroup>(R.id.dismiss)
+ val dismissLabel = dismiss.getChildAt(0)
+ val recommendationText = itemView.requireViewById<TextView>(R.id.recommendation_text)
+ val settings = itemView.requireViewById<View>(R.id.settings)
+
init {
(recommendations.background as IlluminationDrawable).let { background ->
mediaCoverItems.forEach { background.registerLightSource(it) }
mediaLogoItems.forEach { background.registerLightSource(it) }
+ background.registerLightSource(cancel)
+ background.registerLightSource(dismiss)
+ background.registerLightSource(dismissLabel)
+ background.registerLightSource(settings)
}
}
companion object {
/**
- * Creates a PlayerViewHolder.
+ * Creates a RecommendationViewHolder.
*
* @param inflater LayoutInflater to use to inflate the layout.
* @param parent Parent of inflated view.
@@ -76,5 +90,26 @@
itemView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE
return RecommendationViewHolder(itemView)
}
+
+ // Res Ids for the control components on the recommendation view.
+ val controlsIds = setOf(
+ R.id.media_cover1,
+ R.id.media_cover2,
+ R.id.media_cover3,
+ R.id.media_cover4,
+ R.id.media_logo1,
+ R.id.media_logo2,
+ R.id.media_logo3,
+ R.id.media_logo4
+ )
+
+ // Res Ids for the components on the guts panel.
+ val gutsIds = setOf(
+ R.id.recommendation_text,
+ R.id.remove_text,
+ R.id.cancel,
+ R.id.dismiss,
+ R.id.settings
+ )
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java b/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java
index 68a829c..0efef02 100644
--- a/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java
@@ -42,7 +42,7 @@
/** Helper functions to handle notifications in People Tiles. */
public class NotificationHelper {
private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
- private static final String TAG = "PeopleNotificationHelper";
+ private static final String TAG = "PeopleNotifHelper";
/** Returns the notification with highest priority to be shown in People Tiles. */
public static NotificationEntry getHighestPriorityNotification(
@@ -209,5 +209,30 @@
}
return null;
}
+
+ /** Returns whether {@code notification} is a group conversation. */
+ private static boolean isGroupConversation(Notification notification) {
+ return notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION, false);
+ }
+
+ /**
+ * Returns {@code message}'s sender's name if {@code notification} is from a group conversation.
+ */
+ public static CharSequence getSenderIfGroupConversation(Notification notification,
+ Notification.MessagingStyle.Message message) {
+ if (!isGroupConversation(notification)) {
+ if (DEBUG) {
+ Log.d(TAG, "Notification is not from a group conversation, not checking sender.");
+ }
+ return null;
+ }
+ Person person = message.getSenderPerson();
+ if (person == null) {
+ if (DEBUG) Log.d(TAG, "Notification from group conversation doesn't include sender.");
+ return null;
+ }
+ if (DEBUG) Log.d(TAG, "Returning sender from group conversation notification.");
+ return person.getName();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index ff14abe..98d8866 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -132,7 +132,9 @@
/** Sets {@code tileView} with the data in {@code conversation}. */
private void setTileView(PeopleSpaceTileView tileView, PeopleSpaceTile tile) {
try {
- tileView.setName(tile.getUserName().toString());
+ if (tile.getUserName() != null) {
+ tileView.setName(tile.getUserName().toString());
+ }
tileView.setPersonIcon(getPersonIconBitmap(mContext, tile,
getSizeInDp(mContext, R.dimen.avatar_size_for_medium,
mContext.getResources().getDisplayMetrics().density)));
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index eefe5ca..99a17ffb 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -18,6 +18,7 @@
import static com.android.systemui.people.NotificationHelper.getContactUri;
import static com.android.systemui.people.NotificationHelper.getMessagingStyleMessages;
+import static com.android.systemui.people.NotificationHelper.getSenderIfGroupConversation;
import static com.android.systemui.people.NotificationHelper.hasReadContactsPermission;
import static com.android.systemui.people.NotificationHelper.isMissedCall;
import static com.android.systemui.people.NotificationHelper.shouldMatchNotificationByUri;
@@ -233,6 +234,7 @@
// Reset notification content.
.setNotificationKey(null)
.setNotificationContent(null)
+ .setNotificationSender(null)
.setNotificationDataUri(null)
.setMessagesCount(0)
// Reset missed calls category.
@@ -245,9 +247,9 @@
* {@code messagesCount}.
*/
public static PeopleSpaceTile augmentTileFromNotification(Context context, PeopleSpaceTile tile,
- NotificationEntry notificationEntry, int messagesCount) {
+ PeopleTileKey key, NotificationEntry notificationEntry, int messagesCount) {
if (notificationEntry == null || notificationEntry.getSbn().getNotification() == null) {
- if (DEBUG) Log.d(TAG, "Notification is null");
+ if (DEBUG) Log.d(TAG, "Tile key: " + key.toString() + ". Notification is null");
return removeNotificationFields(tile);
}
Notification notification = notificationEntry.getSbn().getNotification();
@@ -256,7 +258,7 @@
getMessagingStyleMessages(notification);
if (!isMissedCall && ArrayUtils.isEmpty(messages)) {
- if (DEBUG) Log.d(TAG, "Notification has no content");
+ if (DEBUG) Log.d(TAG, "Tile key: " + key.toString() + ". Notification has no content");
return removeNotificationFields(tile);
}
@@ -268,13 +270,18 @@
CharSequence content = (isMissedCall && !hasMessageText)
? context.getString(R.string.missed_call) : message.getText();
Uri dataUri = message != null ? message.getDataUri() : null;
- if (DEBUG) Log.d(TAG, "Notification message has text: " + hasMessageText);
+ if (DEBUG) {
+ Log.d(TAG, "Tile key: " + key.toString() + ". Notification message has text: "
+ + hasMessageText);
+ }
+ CharSequence sender = getSenderIfGroupConversation(notification, message);
return tile
.toBuilder()
.setNotificationKey(notificationEntry.getSbn().getKey())
.setNotificationCategory(notification.category)
.setNotificationContent(content)
+ .setNotificationSender(sender)
.setNotificationDataUri(dataUri)
.setMessagesCount(messagesCount)
.build();
@@ -459,7 +466,7 @@
}
if (DEBUG) {
Log.d(TAG, "Widget: " + appWidgetId + ", " + tile.getUserName() + ", "
- + tile.getPackageName());
+ + tile.getPackageName() + ". Updating app widget view.");
}
RemoteViews views = new PeopleTileViewHelper(context, tile, appWidgetId,
options).getViews();
@@ -472,7 +479,9 @@
public static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager,
Context context, int appWidgetId, PeopleSpaceTile tile) {
if (tile == null) {
- Log.d(TAG, "Tile is null, skipping storage and update.");
+ if (DEBUG) {
+ Log.w(TAG, "Widget: " + appWidgetId + "Tile is null, skipping storage and update.");
+ }
return;
}
Bundle options = AppWidgetOptionsHelper.setPeopleTile(appWidgetManager, appWidgetId, tile);
@@ -483,7 +492,10 @@
public static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager,
Context context, int appWidgetId, Optional<PeopleSpaceTile> optionalTile) {
if (!optionalTile.isPresent()) {
- Log.d(TAG, "Tile is null, skipping storage and update.");
+ if (DEBUG) {
+ Log.w(TAG, "Widget: " + appWidgetId
+ + "Optional tile is not present, skipping storage and update.");
+ }
return;
}
updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId, optionalTile.get());
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java b/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java
index 145fee5..81df107 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java
@@ -23,16 +23,17 @@
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
+import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.util.TypedValue;
-import com.android.launcher3.icons.BaseIconFactory;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
-class PeopleStoryIconFactory extends BaseIconFactory {
+class PeopleStoryIconFactory implements AutoCloseable {
private static final int PADDING = 2;
private static final int RING_WIDTH = 2;
@@ -44,11 +45,13 @@
private int mAccentColor;
private float mDensity;
private float mIconSize;
+ private Context mContext;
+
+ private final int mIconBitmapSize;
PeopleStoryIconFactory(Context context, PackageManager pm,
IconDrawableFactory iconDrawableFactory, int iconSizeDp) {
- super(context, context.getResources().getConfiguration().densityDpi,
- (int) (iconSizeDp * context.getResources().getDisplayMetrics().density));
+ mIconBitmapSize = (int) (iconSizeDp * context.getResources().getDisplayMetrics().density);
mDensity = context.getResources().getDisplayMetrics().density;
mIconSize = mDensity * iconSizeDp;
mPackageManager = pm;
@@ -57,6 +60,7 @@
TypedValue typedValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true);
mAccentColor = context.getColor(typedValue.resourceId);
+ mContext = context;
}
@@ -69,7 +73,7 @@
try {
final ApplicationInfo appInfo = mPackageManager.getApplicationInfoAsUser(
packageName, PackageManager.GET_META_DATA, userId);
- badge = mIconDrawableFactory.getBadgedIcon(appInfo, userId);
+ badge = Utils.getBadgedIcon(mContext, appInfo);
} catch (PackageManager.NameNotFoundException e) {
badge = mPackageManager.getDefaultActivityIcon();
}
@@ -209,7 +213,11 @@
@Override
public int getOpacity() {
- return 0;
+ return PixelFormat.TRANSLUCENT;
}
}
-}
+
+ @Override
+ public void close() {
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
index 3883c00..d4ddc65 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
@@ -59,6 +59,7 @@
import com.android.systemui.R;
import com.android.systemui.people.widget.LaunchConversationActivity;
import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
+import com.android.systemui.people.widget.PeopleTileKey;
import java.text.NumberFormat;
import java.time.Duration;
@@ -148,6 +149,8 @@
* content, then birthdays, then the most recent status, and finally last interaction.
*/
private RemoteViews getViewForTile() {
+ PeopleTileKey key = new PeopleTileKey(mTile);
+ if (DEBUG) Log.d(TAG, "Creating view for tile key: " + key.toString());
if (Objects.equals(mTile.getNotificationCategory(), CATEGORY_MISSED_CALL)) {
if (DEBUG) Log.d(TAG, "Create missed call view");
return createMissedCallRemoteViews();
@@ -179,7 +182,7 @@
return createLastInteractionRemoteViews();
}
- private void setMaxLines(RemoteViews views) {
+ private void setMaxLines(RemoteViews views, boolean showSender) {
int textSize = mLayoutSize == LAYOUT_LARGE ? getSizeInDp(
R.dimen.content_text_size_for_medium)
: getSizeInDp(R.dimen.content_text_size_for_medium);
@@ -187,6 +190,9 @@
int notificationContentHeight = getContentHeightForLayout(lineHeight);
int maxAdaptiveLines = Math.floorDiv(notificationContentHeight, lineHeight);
int maxLines = Math.max(MIN_CONTENT_MAX_LINES, maxAdaptiveLines);
+
+ // Save a line for sender's name, if present.
+ if (showSender) maxLines--;
views.setInt(R.id.text_content, "setMaxLines", maxLines);
}
@@ -305,7 +311,9 @@
views.setViewVisibility(R.id.availability, View.GONE);
}
- views.setTextViewText(R.id.name, mTile.getUserName().toString());
+ if (mTile.getUserName() != null) {
+ views.setTextViewText(R.id.name, mTile.getUserName().toString());
+ }
views.setBoolean(R.id.image, "setClipToOutline", true);
views.setImageViewBitmap(R.id.person_icon,
getPersonIconBitmap(mContext, mTile, maxAvatarSize));
@@ -348,7 +356,7 @@
RemoteViews views = getViewForContentLayout();
views.setViewVisibility(R.id.predefined_icon, View.VISIBLE);
views.setViewVisibility(R.id.messages_count, View.GONE);
- setMaxLines(views);
+ setMaxLines(views, false);
views.setTextViewText(R.id.text_content, mTile.getNotificationContent());
views.setImageViewResource(R.id.predefined_icon, R.drawable.ic_phone_missed);
return views;
@@ -356,6 +364,7 @@
private RemoteViews createNotificationRemoteViews() {
RemoteViews views = getViewForContentLayout();
+ CharSequence sender = mTile.getNotificationSender();
Uri image = mTile.getNotificationDataUri();
if (image != null) {
// TODO: Use NotificationInlineImageCache
@@ -364,7 +373,7 @@
views.setViewVisibility(R.id.text_content, View.GONE);
views.setImageViewResource(R.id.predefined_icon, R.drawable.ic_photo_camera);
} else {
- setMaxLines(views);
+ setMaxLines(views, !TextUtils.isEmpty(sender));
CharSequence content = mTile.getNotificationContent();
views = setPunctuationRemoteViewsFields(views, content);
views.setColorAttr(R.id.text_content, "setTextColor", android.R.attr.textColorPrimary);
@@ -380,9 +389,12 @@
views.setViewVisibility(R.id.predefined_icon, View.GONE);
}
}
- // TODO: Set subtext as Group Sender name once storing the name in PeopleSpaceTile and
- // subtract 1 from maxLines when present.
- views.setViewVisibility(R.id.subtext, View.GONE);
+ if (!TextUtils.isEmpty(sender)) {
+ views.setViewVisibility(R.id.subtext, View.VISIBLE);
+ views.setTextViewText(R.id.subtext, sender);
+ } else {
+ views.setViewVisibility(R.id.subtext, View.GONE);
+ }
return views;
}
@@ -412,7 +424,7 @@
}
views.setViewVisibility(R.id.predefined_icon, View.VISIBLE);
views.setViewVisibility(R.id.messages_count, View.GONE);
- setMaxLines(views);
+ setMaxLines(views, false);
// Secondary text color for statuses.
views.setColorAttr(R.id.text_content, "setTextColor", android.R.attr.textColorSecondary);
views.setTextViewText(R.id.text_content, statusText);
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java b/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java
index 7254eec..73c43eb 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java
@@ -41,7 +41,7 @@
PeopleSpaceTile tile) {
Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
if (tile == null) {
- if (DEBUG) Log.d(TAG, "Requested to store null tile");
+ if (DEBUG) Log.w(TAG, "Requested to store null tile");
return options;
}
options.putParcelable(OPTIONS_PEOPLE_TILE, tile);
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index f11c1bd..64a6509 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -236,7 +236,7 @@
@Nullable
public PeopleSpaceTile getTileFromPersistentStorage(PeopleTileKey key) {
if (!key.isValid()) {
- Log.e(TAG, "PeopleTileKey invalid: " + key);
+ Log.e(TAG, "PeopleTileKey invalid: " + key.toString());
return null;
}
@@ -267,7 +267,14 @@
*/
public void updateWidgetsWithNotificationChanged(StatusBarNotification sbn,
PeopleSpaceUtils.NotificationAction notificationAction) {
- if (DEBUG) Log.d(TAG, "updateWidgetsWithNotificationChanged called");
+ if (DEBUG) {
+ Log.d(TAG, "updateWidgetsWithNotificationChanged called");
+ if (notificationAction == PeopleSpaceUtils.NotificationAction.POSTED) {
+ Log.d(TAG, "Notification posted, key: " + sbn.getKey());
+ } else {
+ Log.d(TAG, "Notification removed, key: " + sbn.getKey());
+ }
+ }
if (mIsForTesting) {
updateWidgetsWithNotificationChangedInBackground(sbn, notificationAction);
return;
@@ -282,7 +289,7 @@
PeopleTileKey key = new PeopleTileKey(
sbn.getShortcutId(), sbn.getUser().getIdentifier(), sbn.getPackageName());
if (!key.isValid()) {
- Log.d(TAG, "Invalid key from sbn");
+ Log.d(TAG, "Sbn doesn't contain valid PeopleTileKey: " + key.toString());
return;
}
int[] widgetIds = mAppWidgetManager.getAppWidgetIds(
@@ -309,8 +316,12 @@
/** Updates {@code widgetIdsToUpdate} with {@code action}. */
private void updateWidgetIdsBasedOnNotifications(Set<String> widgetIdsToUpdate) {
- Log.d(TAG, "Fetching grouped notifications");
+ if (widgetIdsToUpdate.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "No widgets to update, returning.");
+ return;
+ }
try {
+ if (DEBUG) Log.d(TAG, "Fetching grouped notifications");
Map<PeopleTileKey, Set<NotificationEntry>> groupedNotifications =
getGroupedConversationNotifications();
@@ -331,14 +342,15 @@
* Augments {@code tile} based on notifications returned from {@code notificationEntryManager}.
*/
public PeopleSpaceTile augmentTileFromNotificationEntryManager(PeopleSpaceTile tile) {
- Log.d(TAG, "Augmenting tile from NotificationEntryManager widget: " + tile.getId());
+ PeopleTileKey key = new PeopleTileKey(tile);
+ Log.d(TAG, "Augmenting tile from NotificationEntryManager widget: " + key.toString());
Map<PeopleTileKey, Set<NotificationEntry>> notifications =
getGroupedConversationNotifications();
String contactUri = null;
if (tile.getContactUri() != null) {
contactUri = tile.getContactUri().toString();
}
- return augmentTileFromNotifications(tile, contactUri, notifications);
+ return augmentTileFromNotifications(tile, key, contactUri, notifications);
}
/** Returns active and pending notifications grouped by {@link PeopleTileKey}. */
@@ -367,9 +379,9 @@
}
/** Augments {@code tile} based on {@code notifications}, matching {@code contactUri}. */
- public PeopleSpaceTile augmentTileFromNotifications(PeopleSpaceTile tile, String contactUri,
- Map<PeopleTileKey, Set<NotificationEntry>> notifications) {
- if (DEBUG) Log.d(TAG, "Augmenting tile from notifications. Tile id: " + tile.getId());
+ public PeopleSpaceTile augmentTileFromNotifications(PeopleSpaceTile tile, PeopleTileKey key,
+ String contactUri, Map<PeopleTileKey, Set<NotificationEntry>> notifications) {
+ if (DEBUG) Log.d(TAG, "Augmenting tile from notifications. Tile key: " + key.toString());
boolean hasReadContactsPermission = mPackageManager.checkPermission(READ_CONTACTS,
tile.getPackageName()) == PackageManager.PERMISSION_GRANTED;
@@ -384,13 +396,12 @@
}
}
- PeopleTileKey key = new PeopleTileKey(tile);
Set<NotificationEntry> allNotifications = notifications.get(key);
if (allNotifications == null) {
allNotifications = new HashSet<>();
}
if (allNotifications.isEmpty() && notificationsByUri.isEmpty()) {
- if (DEBUG) Log.d(TAG, "No existing notifications for tile: " + key);
+ if (DEBUG) Log.d(TAG, "No existing notifications for tile: " + key.toString());
return removeNotificationFields(tile);
}
@@ -402,22 +413,28 @@
NotificationEntry highestPriority = getHighestPriorityNotification(allNotifications);
if (DEBUG) Log.d(TAG, "Augmenting tile from notification, key: " + key.toString());
- return augmentTileFromNotification(mContext, tile, highestPriority, messagesCount);
+ return augmentTileFromNotification(mContext, tile, key, highestPriority, messagesCount);
}
/** Returns an augmented tile for an existing widget. */
@Nullable
public Optional<PeopleSpaceTile> getAugmentedTileForExistingWidget(int widgetId,
Map<PeopleTileKey, Set<NotificationEntry>> notifications) {
- Log.d(TAG, "Augmenting tile for widget: " + widgetId);
+ Log.d(TAG, "Augmenting tile for existing widget: " + widgetId);
PeopleSpaceTile tile = getTileForExistingWidget(widgetId);
if (tile == null) {
+ if (DEBUG) {
+ Log.w(TAG, "Widget: " + widgetId
+ + ". Null tile for existing widget, skipping update.");
+ }
return Optional.empty();
}
String contactUriString = mSharedPrefs.getString(String.valueOf(widgetId), null);
// Should never be null, but using ofNullable for extra safety.
+ PeopleTileKey key = new PeopleTileKey(tile);
+ if (DEBUG) Log.d(TAG, "Existing widget: " + widgetId + ". Tile key: " + key.toString());
return Optional.ofNullable(
- augmentTileFromNotifications(tile, contactUriString, notifications));
+ augmentTileFromNotifications(tile, key, contactUriString, notifications));
}
/** Returns stored widgets for the conversation specified. */
@@ -644,12 +661,12 @@
}
synchronized (mLock) {
- if (DEBUG) Log.d(TAG, "Add storage for : " + tile.getId());
+ if (DEBUG) Log.d(TAG, "Add storage for : " + key.toString());
PeopleSpaceUtils.setSharedPreferencesStorageForTile(mContext, key, appWidgetId,
tile.getContactUri());
}
try {
- if (DEBUG) Log.d(TAG, "Caching shortcut for PeopleTile: " + tile.getId());
+ if (DEBUG) Log.d(TAG, "Caching shortcut for PeopleTile: " + key.toString());
mLauncherApps.cacheShortcuts(tile.getPackageName(),
Collections.singletonList(tile.getId()),
tile.getUserHandle(), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS);
@@ -679,7 +696,7 @@
if (DEBUG) Log.d(TAG, "Already registered listener");
return;
}
- if (DEBUG) Log.d(TAG, "Register listener for " + widgetId + " with " + key);
+ if (DEBUG) Log.d(TAG, "Register listener for " + widgetId + " with " + key.toString());
mListeners.put(key, newListener);
}
mPeopleManager.registerConversationListener(key.getPackageName(),
@@ -750,7 +767,9 @@
if (DEBUG) Log.d(TAG, "Cannot find listener to unregister");
return;
}
- if (DEBUG) Log.d(TAG, "Unregister listener for " + appWidgetId + " with " + key);
+ if (DEBUG) {
+ Log.d(TAG, "Unregister listener for " + appWidgetId + " with " + key.toString());
+ }
mListeners.remove(key);
}
mPeopleManager.unregisterConversationListener(registeredListener);
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
index feb27d80..a626681 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
@@ -179,12 +179,16 @@
}
uiExecutor.execute {
val elements = filterAndSelect(items)
- val d = dialogProvider.makeDialog(context, elements, this::startActivity)
- d.setShowForAllUsers(true)
- d.addOnDismissListener(onDialogDismissed)
- d.show()
- privacyLogger.logShowDialogContents(elements)
- dialog = d
+ if (elements.isNotEmpty()) {
+ val d = dialogProvider.makeDialog(context, elements, this::startActivity)
+ d.setShowForAllUsers(true)
+ d.addOnDismissListener(onDialogDismissed)
+ d.show()
+ privacyLogger.logShowDialogContents(elements)
+ dialog = d
+ } else {
+ Log.w(TAG, "Trying to show empty dialog")
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
index 63ec6e5..76199bf 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
@@ -58,7 +58,7 @@
val paused: Boolean = false
) {
val log = "(${privacyType.logName}, ${application.packageName}(${application.uid}), " +
- "$timeStampElapsed)"
+ "$timeStampElapsed, paused=$paused)"
}
data class PrivacyApplication(val packageName: String, val uid: Int)
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
index acce945..7c82a82 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
@@ -116,6 +116,12 @@
})
}
+ fun logEmptyDialog() {
+ log(LogLevel.WARNING, {}, {
+ "Trying to show an empty dialog"
+ })
+ }
+
fun logPrivacyDialogDismissed() {
log(LogLevel.INFO, {}, {
"Privacy dialog dismissed"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/NonInterceptingScrollView.java b/packages/SystemUI/src/com/android/systemui/qs/NonInterceptingScrollView.java
index 309b32f..cd36091 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/NonInterceptingScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/NonInterceptingScrollView.java
@@ -29,6 +29,7 @@
private final int mTouchSlop;
private float mDownY;
+ private boolean mScrollEnabled = true;
public NonInterceptingScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -85,6 +86,16 @@
return super.onInterceptTouchEvent(ev);
}
+ @Override
+ public boolean canScrollVertically(int direction) {
+ return mScrollEnabled && super.canScrollVertically(direction);
+ }
+
+ @Override
+ public boolean canScrollHorizontally(int direction) {
+ return mScrollEnabled && super.canScrollHorizontally(direction);
+ }
+
public int getScrollRange() {
int scrollRange = 0;
if (getChildCount() > 0) {
@@ -94,4 +105,12 @@
}
return scrollRange;
}
+
+ /**
+ * Enable scrolling for this view. Needed because the view might be clipped but still intercepts
+ * touches on the lockscreen.
+ */
+ public void setScrollingEnabled(boolean enabled) {
+ mScrollEnabled = enabled;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index cefcd4a..294d765 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -54,6 +54,7 @@
private static final String MOVE_FULL_ROWS = "sysui_qs_move_whole_rows";
public static final float EXPANDED_TILE_DELAY = .86f;
+ public static final float SHORT_PARALLAX_AMOUNT = 0.1f;
private static final long QQS_FADE_IN_DURATION = 200L;
// Fade out faster than fade in to finish before QQS hides.
private static final long QQS_FADE_OUT_DURATION = 50L;
@@ -101,6 +102,7 @@
private final Executor mExecutor;
private final TunerService mTunerService;
private boolean mShowCollapsedOnKeyguard;
+ private boolean mTranslateWhileExpanding;
@Inject
public QSAnimator(QS qs, QuickQSPanel quickPanel, QuickStatusBarHeader quickStatusBarHeader,
@@ -242,6 +244,9 @@
int width = mQs.getView() != null ? mQs.getView().getMeasuredWidth() : 0;
int heightDiff = height - mQs.getHeader().getBottom()
+ mQs.getHeader().getPaddingBottom();
+ if (!mTranslateWhileExpanding) {
+ heightDiff *= SHORT_PARALLAX_AMOUNT;
+ }
firstPageBuilder.addFloat(tileLayout, "translationY", heightDiff, 0);
int qqsTileHeight = 0;
@@ -570,6 +575,13 @@
setCurrentPosition();
};
+ /**
+ * True whe QS will be pulled from the top, false when it will be clipped.
+ */
+ public void setTranslateWhileExpanding(boolean shouldTranslate) {
+ mTranslateWhileExpanding = shouldTranslate;
+ }
+
static class HeightExpansionAnimator {
private final List<View> mViews = new ArrayList<>();
private final ValueAnimator mAnimator;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 6b09e2e..e89803d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -20,6 +20,8 @@
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Canvas;
+import android.graphics.Path;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.View;
@@ -54,6 +56,10 @@
private static final PhysicsAnimator.SpringConfig BACKGROUND_SPRING
= new PhysicsAnimator.SpringConfig(SpringForce.STIFFNESS_MEDIUM,
SpringForce.DAMPING_RATIO_LOW_BOUNCY);
+ private int mFancyClippingTop;
+ private int mFancyClippingBottom;
+ private final float[] mFancyClippingRadii = new float[] {0, 0, 0, 0, 0, 0, 0, 0};
+ private final Path mFancyClippingPath = new Path();
private int mBackgroundBottom = -1;
private int mHeightOverride = -1;
private View mQSDetail;
@@ -70,6 +76,7 @@
private int mContentPadding = -1;
private boolean mAnimateBottomOnNextLayout;
private int mNavBarInset = 0;
+ private boolean mClippingEnabled;
public QSContainerImpl(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -169,6 +176,15 @@
MeasureSpec.makeMeasureSpec(getDisplayHeight(), MeasureSpec.EXACTLY));
}
+ @Override
+ public void dispatchDraw(Canvas canvas) {
+ if (!mFancyClippingPath.isEmpty()) {
+ canvas.translate(0, -getTranslationY());
+ canvas.clipOutPath(mFancyClippingPath);
+ canvas.translate(0, getTranslationY());
+ }
+ super.dispatchDraw(canvas);
+ }
@Override
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
@@ -187,6 +203,7 @@
super.onLayout(changed, left, top, right, bottom);
updateExpansion(mAnimateBottomOnNextLayout /* animate */);
mAnimateBottomOnNextLayout = false;
+ updateClippingPath();
}
public void disable(int state1, int state2, boolean animate) {
@@ -281,6 +298,7 @@
public void setExpansion(float expansion) {
mQsExpansion = expansion;
+ mQSPanelContainer.setScrollingEnabled(expansion > 0.0f);
updateExpansion();
}
@@ -318,4 +336,46 @@
}
return mSizePoint.y;
}
+
+ /**
+ * Clip QS bottom using a concave shape.
+ */
+ public void setFancyClipping(int top, int bottom, int radius, boolean enabled) {
+ boolean updatePath = false;
+ if (mFancyClippingRadii[0] != radius) {
+ mFancyClippingRadii[0] = radius;
+ mFancyClippingRadii[1] = radius;
+ mFancyClippingRadii[2] = radius;
+ mFancyClippingRadii[3] = radius;
+ updatePath = true;
+ }
+ if (mFancyClippingTop != top) {
+ mFancyClippingTop = top;
+ updatePath = true;
+ }
+ if (mFancyClippingBottom != bottom) {
+ mFancyClippingBottom = bottom;
+ updatePath = true;
+ }
+ if (mClippingEnabled != enabled) {
+ mClippingEnabled = enabled;
+ updatePath = true;
+ }
+
+ if (updatePath) {
+ updateClippingPath();
+ }
+ }
+
+ private void updateClippingPath() {
+ mFancyClippingPath.reset();
+ if (!mClippingEnabled) {
+ invalidate();
+ return;
+ }
+
+ mFancyClippingPath.addRoundRect(0, mFancyClippingTop, getWidth(),
+ mFancyClippingBottom, mFancyClippingRadii, Path.Direction.CW);
+ invalidate();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
index c4986cc..40967ed 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
@@ -195,10 +195,10 @@
mExpandClickListener = onClickListener;
}
- void setExpanded(boolean expanded, boolean isTunerEnabled) {
+ void setExpanded(boolean expanded, boolean isTunerEnabled, boolean multiUserEnabled) {
if (mExpanded == expanded) return;
mExpanded = expanded;
- updateEverything(isTunerEnabled);
+ updateEverything(isTunerEnabled, multiUserEnabled);
}
/** */
@@ -251,16 +251,16 @@
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
}
- void disable(int state2, boolean isTunerEnabled) {
+ void disable(int state2, boolean isTunerEnabled, boolean multiUserEnabled) {
final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
if (disabled == mQsDisabled) return;
mQsDisabled = disabled;
- updateEverything(isTunerEnabled);
+ updateEverything(isTunerEnabled, multiUserEnabled);
}
- void updateEverything(boolean isTunerEnabled) {
+ void updateEverything(boolean isTunerEnabled, boolean multiUserEnabled) {
post(() -> {
- updateVisibilities(isTunerEnabled);
+ updateVisibilities(isTunerEnabled, multiUserEnabled);
updateClickabilities();
setClickable(false);
});
@@ -273,18 +273,19 @@
mBuildText.setLongClickable(mBuildText.getVisibility() == View.VISIBLE);
}
- private void updateVisibilities(boolean isTunerEnabled) {
+ private void updateVisibilities(boolean isTunerEnabled, boolean multiUserEnabled) {
mSettingsContainer.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
mTunerIcon.setVisibility(isTunerEnabled ? View.VISIBLE : View.INVISIBLE);
final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
- mMultiUserSwitch.setVisibility(showUserSwitcher() ? View.VISIBLE : View.GONE);
+ mMultiUserSwitch.setVisibility(
+ showUserSwitcher(multiUserEnabled) ? View.VISIBLE : View.GONE);
mSettingsButton.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
mBuildText.setVisibility(mExpanded && mShouldShowBuildText ? View.VISIBLE : View.INVISIBLE);
}
- private boolean showUserSwitcher() {
- return mExpanded && mMultiUserSwitch.isMultiUserEnabled();
+ private boolean showUserSwitcher(boolean multiUserEnabled) {
+ return mExpanded && multiUserEnabled;
}
void onUserInfoChanged(Drawable picture, boolean isGuestUser) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index 74ae3a6..1fa9260 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -38,7 +38,7 @@
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.phone.MultiUserSwitch;
+import com.android.systemui.statusbar.phone.MultiUserSwitchController;
import com.android.systemui.statusbar.phone.SettingsButton;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.UserInfoController;
@@ -60,16 +60,15 @@
private final DeviceProvisionedController mDeviceProvisionedController;
private final UserTracker mUserTracker;
private final QSPanelController mQsPanelController;
- private final QSDetailDisplayer mQsDetailDisplayer;
private final QuickQSPanelController mQuickQSPanelController;
private final TunerService mTunerService;
private final MetricsLogger mMetricsLogger;
private final FalsingManager mFalsingManager;
+ private final MultiUserSwitchController mMultiUserSwitchController;
private final SettingsButton mSettingsButton;
private final View mSettingsButtonContainer;
private final TextView mBuildText;
private final View mEdit;
- private final MultiUserSwitch mMultiUserSwitch;
private final PageIndicator mPageIndicator;
private final View mPowerMenuLite;
private final boolean mShowPMLiteButton;
@@ -135,7 +134,8 @@
QSFooterViewController(QSFooterView view, UserManager userManager,
UserInfoController userInfoController, ActivityStarter activityStarter,
DeviceProvisionedController deviceProvisionedController, UserTracker userTracker,
- QSPanelController qsPanelController, QSDetailDisplayer qsDetailDisplayer,
+ QSPanelController qsPanelController,
+ MultiUserSwitchController multiUserSwitchController,
QuickQSPanelController quickQSPanelController,
TunerService tunerService, MetricsLogger metricsLogger, FalsingManager falsingManager,
@Named(PM_LITE_ENABLED) boolean showPMLiteButton,
@@ -147,17 +147,16 @@
mDeviceProvisionedController = deviceProvisionedController;
mUserTracker = userTracker;
mQsPanelController = qsPanelController;
- mQsDetailDisplayer = qsDetailDisplayer;
mQuickQSPanelController = quickQSPanelController;
mTunerService = tunerService;
mMetricsLogger = metricsLogger;
mFalsingManager = falsingManager;
+ mMultiUserSwitchController = multiUserSwitchController;
mSettingsButton = mView.findViewById(R.id.settings_button);
mSettingsButtonContainer = mView.findViewById(R.id.settings_button_container);
mBuildText = mView.findViewById(R.id.build);
mEdit = mView.findViewById(android.R.id.edit);
- mMultiUserSwitch = mView.findViewById(R.id.multi_user_switch);
mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
mPowerMenuLite = mView.findViewById(R.id.pm_lite);
mShowPMLiteButton = showPMLiteButton;
@@ -165,6 +164,12 @@
}
@Override
+ protected void onInit() {
+ super.onInit();
+ mMultiUserSwitchController.init();
+ }
+
+ @Override
protected void onViewAttached() {
if (mShowPMLiteButton) {
mPowerMenuLite.setVisibility(View.VISIBLE);
@@ -199,9 +204,8 @@
mQsPanelController.showEdit(view));
});
- mMultiUserSwitch.setQSDetailDisplayer(mQsDetailDisplayer);
mQsPanelController.setFooterPageIndicator(mPageIndicator);
- mView.updateEverything(isTunerEnabled());
+ mView.updateEverything(isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled());
}
@Override
@@ -217,10 +221,10 @@
@Override
public void setExpanded(boolean expanded) {
mExpanded = expanded;
- mView.setExpanded(expanded, isTunerEnabled());
+ mView.setExpanded(
+ expanded, isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled());
}
-
@Override
public int getHeight() {
return mView.getHeight();
@@ -258,7 +262,7 @@
@Override
public void disable(int state1, int state2, boolean animate) {
- mView.disable(state2, isTunerEnabled());
+ mView.disable(state2, isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled());
}
private void startSettingsActivity() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index b95194a..d5cb777 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -107,6 +107,11 @@
private QuickQSPanelController mQuickQSPanelController;
private QSCustomizerController mQSCustomizerController;
private FeatureFlags mFeatureFlags;
+ /**
+ * When true, QS will translate from outside the screen. It will be clipped with parallax
+ * otherwise.
+ */
+ private boolean mTranslateWhileExpanding;
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
@@ -254,6 +259,13 @@
}
}
+ @Override
+ public void setFancyClipping(int top, int bottom, int cornerRadius, boolean visible) {
+ if (getView() instanceof QSContainerImpl) {
+ ((QSContainerImpl) getView()).setFancyClipping(top, bottom, cornerRadius, visible);
+ }
+ }
+
private void setEditLocation(View view) {
View edit = view.findViewById(android.R.id.edit);
int[] loc = edit.getLocationOnScreen();
@@ -394,16 +406,23 @@
}
@Override
+ public void setTranslateWhileExpanding(boolean shouldTranslate) {
+ mTranslateWhileExpanding = shouldTranslate;
+ mQSAnimator.setTranslateWhileExpanding(shouldTranslate);
+ }
+
+ @Override
public void setQsExpansion(float expansion, float headerTranslation) {
if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
if (mQSAnimator != null) {
final boolean showQSOnLockscreen = expansion > 0;
- final boolean showQSUnlocked = headerTranslation == 0;
+ final boolean showQSUnlocked = headerTranslation == 0 || !mTranslateWhileExpanding;
mQSAnimator.startAlphaAnimation(showQSOnLockscreen || showQSUnlocked);
}
mContainer.setExpansion(expansion);
- final float translationScaleY = expansion - 1;
+ final float translationScaleY = (mTranslateWhileExpanding
+ ? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1);
boolean onKeyguardAndExpanded = isKeyguardShowing() && !mShowCollapsedOnKeyguard;
if (!mHeaderAnimating && !headerWillBeAnimating()) {
getView().setTranslationY(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index f89e70a..efa1a13 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -326,6 +326,7 @@
super.onConfigurationChanged(newConfig);
mOnConfigurationChangedListeners.forEach(
listener -> listener.onConfigurationChange(newConfig));
+ switchSecurityFooter();
}
@Override
@@ -364,19 +365,25 @@
switchToParent((View) newLayout, parent, index);
index++;
- if (mSecurityFooter != null) {
- if (mUsingHorizontalLayout && mHeaderContainer != null) {
- // Adding the security view to the header, that enables us to avoid scrolling
- switchToParent(mSecurityFooter, mHeaderContainer, 0);
- } else {
- switchToParent(mSecurityFooter, parent, index);
- index++;
- }
- }
-
if (mFooter != null) {
// Then the footer with the settings
switchToParent(mFooter, parent, index);
+ index++;
+ }
+
+ // The security footer is switched on orientation changes
+ }
+
+ private void switchSecurityFooter() {
+ if (mSecurityFooter != null) {
+ if (mContext.getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_LANDSCAPE && mHeaderContainer != null
+ && !mSecurityFooter.getParent().equals(mHeaderContainer)) {
+ // Adding the security view to the header, that enables us to avoid scrolling
+ switchToParent(mSecurityFooter, mHeaderContainer, 0);
+ } else {
+ switchToParent(mSecurityFooter, this, -1);
+ }
}
}
@@ -668,6 +675,7 @@
public void setSecurityFooter(View view) {
mSecurityFooter = view;
+ switchSecurityFooter();
}
void setUsingHorizontalLayout(boolean horizontal, ViewGroup mediaHostView, boolean force,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 670475f..baf781d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.systemui.qs.dagger.QSFragmentModule.QS_SECURITY_FOOTER_VIEW;
@@ -26,6 +28,8 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.UserInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
@@ -68,7 +72,6 @@
private final View mRootView;
private final TextView mFooterText;
- private final ImageView mFooterIcon;
private final ImageView mPrimaryFooterIcon;
private final Context mContext;
private final Callback mCallback = new Callback();
@@ -83,7 +86,6 @@
private boolean mIsVisible;
private CharSequence mFooterTextContent = null;
- private int mFooterTextId;
private int mFooterIconId;
private Drawable mPrimaryFooterIconDrawable;
@@ -94,7 +96,6 @@
mRootView = rootView;
mRootView.setOnClickListener(this);
mFooterText = mRootView.findViewById(R.id.footer_text);
- mFooterIcon = mRootView.findViewById(R.id.footer_icon);
mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon);
mFooterIconId = R.drawable.ic_info_outline;
mContext = rootView.getContext();
@@ -120,6 +121,23 @@
public void onConfigurationChanged() {
FontSizeUtils.updateFontSize(mFooterText, R.dimen.qs_tile_text_size);
+
+ Resources r = mContext.getResources();
+
+ mFooterText.setMaxLines(r.getInteger(R.integer.qs_security_footer_maxLines));
+ int padding = r.getDimensionPixelSize(R.dimen.qs_footer_padding);
+ mRootView.setPaddingRelative(padding, padding, padding, padding);
+
+ int verticalMargin = r.getDimensionPixelSize(R.dimen.qs_security_footer_vertical_margin);
+ ViewGroup.MarginLayoutParams lp =
+ (ViewGroup.MarginLayoutParams) mRootView.getLayoutParams();
+ lp.topMargin = verticalMargin;
+ lp.bottomMargin = verticalMargin;
+ lp.width = r.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT
+ ? MATCH_PARENT : WRAP_CONTENT;
+ mRootView.setLayoutParams(lp);
+
+ mRootView.setBackground(mContext.getDrawable(R.drawable.qs_security_footer_background));
}
public View getView() {
@@ -189,7 +207,6 @@
}
if (mFooterIconId != footerIconId) {
mFooterIconId = footerIconId;
- mMainHandler.post(mUpdateIcon);
}
// Update the primary icon
@@ -315,7 +332,7 @@
mDialog.setView(createDialogView());
mDialog.show();
- mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
+ mDialog.getWindow().setLayout(MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
@@ -575,19 +592,14 @@
== DEVICE_OWNER_TYPE_FINANCED;
}
- private final Runnable mUpdateIcon = new Runnable() {
- @Override
- public void run() {
- mFooterIcon.setImageResource(mFooterIconId);
- }
- };
-
private final Runnable mUpdatePrimaryIcon = new Runnable() {
@Override
public void run() {
- mPrimaryFooterIcon.setVisibility(mPrimaryFooterIconDrawable != null
- ? View.VISIBLE : View.GONE);
- mPrimaryFooterIcon.setImageDrawable(mPrimaryFooterIconDrawable);
+ if (mPrimaryFooterIconDrawable != null) {
+ mPrimaryFooterIcon.setImageDrawable(mPrimaryFooterIconDrawable);
+ } else {
+ mPrimaryFooterIcon.setImageResource(mFooterIconId);
+ }
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index 3a5adce..34aac49 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -34,6 +34,7 @@
import com.android.systemui.qs.QuickQSPanel;
import com.android.systemui.qs.QuickStatusBarHeader;
import com.android.systemui.qs.customize.QSCustomizer;
+import com.android.systemui.statusbar.phone.MultiUserSwitch;
import javax.inject.Named;
@@ -74,6 +75,12 @@
/** */
@Provides
+ static MultiUserSwitch providesMultiUserSWitch(QSFooterView qsFooterView) {
+ return qsFooterView.findViewById(R.id.multi_user_switch);
+ }
+
+ /** */
+ @Provides
static QSPanel provideQSPanel(@RootView View view) {
return view.findViewById(R.id.quick_settings_panel);
}
@@ -129,7 +136,7 @@
@QSThemedContext LayoutInflater layoutInflater,
QSPanel qsPanel
) {
- return layoutInflater.inflate(R.layout.quick_settings_footer, qsPanel, false);
+ return layoutInflater.inflate(R.layout.quick_settings_security_footer, qsPanel, false);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
index 2168b1f..71f42d8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
@@ -20,7 +20,6 @@
import android.content.Intent
import android.os.Handler
import android.os.Looper
-import android.provider.Settings
import android.service.quicksettings.Tile
import android.view.View
import com.android.internal.logging.MetricsLogger
@@ -66,7 +65,6 @@
) {
private var hasControlsApps = AtomicBoolean(false)
- private val intent = Intent(Settings.ACTION_DEVICE_CONTROLS_SETTINGS)
private val icon = ResourceIcon.get(R.drawable.ic_device_light)
@@ -91,13 +89,10 @@
override fun newTileState(): QSTile.State {
return QSTile.State().also {
it.state = Tile.STATE_UNAVAILABLE // Start unavailable matching `hasControlsApps`
+ it.handlesLongClick = false
}
}
- override fun handleDestroy() {
- super.handleDestroy()
- }
-
override fun handleClick(view: View?) {
if (state.state == Tile.STATE_ACTIVE) {
mUiHandler.post {
@@ -138,10 +133,12 @@
return 0
}
- override fun getLongClickIntent(): Intent {
- return intent
+ override fun getLongClickIntent(): Intent? {
+ return null
}
+ override fun handleLongClick(view: View?) {}
+
override fun getTileLabel(): CharSequence {
return mContext.getText(R.string.quick_controls_title)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 8ddd4c9..2458223 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -34,10 +34,13 @@
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.R;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.qs.PseudoGridView;
import com.android.systemui.qs.QSUserSwitcherEvent;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import javax.inject.Inject;
+
/**
* Quick settings detail view for user switching.
*/
@@ -54,9 +57,9 @@
R.layout.qs_user_detail, parent, attach);
}
- public void createAndSetAdapter(UserSwitcherController controller,
- UiEventLogger uiEventLogger) {
- mAdapter = new Adapter(mContext, controller, uiEventLogger);
+ /** Set a {@link android.widget.BaseAdapter} */
+ public void setAdapter(Adapter adapter) {
+ mAdapter = adapter;
ViewGroupAdapterBridge.link(this, mAdapter);
}
@@ -71,13 +74,16 @@
protected UserSwitcherController mController;
private View mCurrentUserView;
private final UiEventLogger mUiEventLogger;
+ private final FalsingManager mFalsingManager;
+ @Inject
public Adapter(Context context, UserSwitcherController controller,
- UiEventLogger uiEventLogger) {
+ UiEventLogger uiEventLogger, FalsingManager falsingManager) {
super(controller);
mContext = context;
mController = controller;
mUiEventLogger = uiEventLogger;
+ mFalsingManager = falsingManager;
}
@Override
@@ -140,6 +146,10 @@
@Override
public void onClick(View view) {
+ if (mFalsingManager.isFalseTap(FalsingManager.MODERATE_PENALTY)) {
+ return;
+ }
+
UserSwitcherController.UserRecord tag =
(UserSwitcherController.UserRecord) view.getTag();
if (tag.isDisabledByAdmin) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index 0106f43..b5e51c6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -20,6 +20,8 @@
import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
import static com.android.systemui.screenshot.LogConfig.DEBUG_STORAGE;
import static com.android.systemui.screenshot.LogConfig.logTag;
+import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType.QUICK_SHARE_ACTION;
+import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType.REGULAR_SMART_ACTIONS;
import android.app.ActivityTaskManager;
import android.app.Notification;
@@ -74,6 +76,7 @@
private final ScreenshotSmartActions mScreenshotSmartActions;
private final ScreenshotController.SaveImageInBackgroundData mParams;
private final ScreenshotController.SavedImageData mImageData;
+ private final ScreenshotController.QuickShareData mQuickShareData;
private final ScreenshotNotificationSmartActionsProvider mSmartActionsProvider;
private String mScreenshotId;
@@ -90,6 +93,7 @@
mContext = context;
mScreenshotSmartActions = screenshotSmartActions;
mImageData = new ScreenshotController.SavedImageData();
+ mQuickShareData = new ScreenshotController.QuickShareData();
mSharedElementTransition = sharedElementTransition;
mImageExporter = exporter;
@@ -127,6 +131,13 @@
Bitmap image = mParams.image;
mScreenshotId = String.format(SCREENSHOT_ID_TEMPLATE, requestId);
try {
+ if (mSmartActionsEnabled && mParams.mQuickShareActionsReadyListener != null) {
+ // Since Quick Share target recommendation does not rely on image URL, it is
+ // queried and surfaced before image compress/export. Action intent would not be
+ // used, because it does not contain image URL.
+ queryQuickShareAction(image, user);
+ }
+
// Call synchronously here since already on a background thread.
ListenableFuture<ImageExporter.Result> future =
mImageExporter.export(Runnable::run, requestId, image);
@@ -136,7 +147,7 @@
CompletableFuture<List<Notification.Action>> smartActionsFuture =
mScreenshotSmartActions.getSmartActionsFuture(
- mScreenshotId, uri, image, mSmartActionsProvider,
+ mScreenshotId, uri, image, mSmartActionsProvider, REGULAR_SMART_ACTIONS,
mSmartActionsEnabled, user);
List<Notification.Action> smartActions = new ArrayList<>();
@@ -148,7 +159,7 @@
smartActions.addAll(buildSmartActions(
mScreenshotSmartActions.getSmartActions(
mScreenshotId, smartActionsFuture, timeoutMs,
- mSmartActionsProvider),
+ mSmartActionsProvider, REGULAR_SMART_ACTIONS),
mContext));
}
@@ -157,6 +168,8 @@
mImageData.shareTransition = createShareAction(mContext, mContext.getResources(), uri);
mImageData.editTransition = createEditAction(mContext, mContext.getResources(), uri);
mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri);
+ mImageData.quickShareAction = createQuickShareAction(mContext,
+ mQuickShareData.quickShareAction, uri);
mParams.mActionsReadyListener.onActionsReady(mImageData);
if (DEBUG_CALLBACK) {
@@ -173,6 +186,7 @@
}
mParams.clearImage();
mImageData.reset();
+ mQuickShareData.reset();
mParams.mActionsReadyListener.onActionsReady(mImageData);
if (DEBUG_CALLBACK) {
Log.d(TAG, "Calling (Consumer<Uri>) finisher.accept(null)");
@@ -197,6 +211,7 @@
// params. The finisher is expected to always be called back, so just use the baked-in
// params from the ctor in any case.
mImageData.reset();
+ mQuickShareData.reset();
mParams.mActionsReadyListener.onActionsReady(mImageData);
if (DEBUG_CALLBACK) {
Log.d(TAG, "onCancelled, calling (Consumer<Uri>) finisher.accept(null)");
@@ -389,4 +404,74 @@
.putExtra(ScreenshotController.EXTRA_ID, screenshotId)
.putExtra(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED, smartActionsEnabled);
}
+
+ /**
+ * Populate image uri into intent of Quick Share action.
+ */
+ @VisibleForTesting
+ private Notification.Action createQuickShareAction(Context context, Notification.Action action,
+ Uri uri) {
+ if (action == null) {
+ return null;
+ }
+ // Populate image URI into Quick Share chip intent
+ Intent sharingIntent = action.actionIntent.getIntent();
+ sharingIntent.setType("image/png");
+ sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
+ String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
+ String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
+ sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
+ // Include URI in ClipData also, so that grantPermission picks it up.
+ // We don't use setData here because some apps interpret this as "to:".
+ ClipData clipdata = new ClipData(new ClipDescription("content",
+ new String[]{"image/png"}),
+ new ClipData.Item(uri));
+ sharingIntent.setClipData(clipdata);
+ sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ PendingIntent updatedPendingIntent = PendingIntent.getActivity(
+ context, 0, sharingIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+
+ // Proxy smart actions through {@link GlobalScreenshot.SmartActionsReceiver}
+ // for logging smart actions.
+ Bundle extras = action.getExtras();
+ String actionType = extras.getString(
+ ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
+ ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE);
+ Intent intent = new Intent(context, SmartActionsReceiver.class)
+ .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, updatedPendingIntent)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ addIntentExtras(mScreenshotId, intent, actionType, mSmartActionsEnabled);
+ PendingIntent broadcastIntent = PendingIntent.getBroadcast(context,
+ mRandom.nextInt(),
+ intent,
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+ return new Notification.Action.Builder(action.getIcon(), action.title,
+ broadcastIntent).setContextual(true).addExtras(extras).build();
+ }
+
+ /**
+ * Query and surface Quick Share chip if it is available. Action intent would not be used,
+ * because it does not contain image URL which would be populated in {@link
+ * #createQuickShareAction(Context, Notification.Action, Uri)}
+ */
+ private void queryQuickShareAction(Bitmap image, UserHandle user) {
+ CompletableFuture<List<Notification.Action>> quickShareActionsFuture =
+ mScreenshotSmartActions.getSmartActionsFuture(
+ mScreenshotId, null, image, mSmartActionsProvider,
+ QUICK_SHARE_ACTION,
+ mSmartActionsEnabled, user);
+ int timeoutMs = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.SCREENSHOT_NOTIFICATION_QUICK_SHARE_ACTIONS_TIMEOUT_MS,
+ 500);
+ List<Notification.Action> quickShareActions =
+ mScreenshotSmartActions.getSmartActions(
+ mScreenshotId, quickShareActionsFuture, timeoutMs,
+ mSmartActionsProvider, QUICK_SHARE_ACTION);
+ if (!quickShareActions.isEmpty()) {
+ mQuickShareData.quickShareAction = quickShareActions.get(0);
+ mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 9d01986..7c2d476 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -114,6 +114,7 @@
public Bitmap image;
public Consumer<Uri> finisher;
public ScreenshotController.ActionsReadyListener mActionsReadyListener;
+ public ScreenshotController.QuickShareActionReadyListener mQuickShareActionsReadyListener;
void clearImage() {
image = null;
@@ -129,6 +130,7 @@
public Supplier<ActionTransition> editTransition;
public Notification.Action deleteAction;
public List<Notification.Action> smartActions;
+ public Notification.Action quickShareAction;
/**
* POD for shared element transition.
@@ -148,6 +150,21 @@
editTransition = null;
deleteAction = null;
smartActions = null;
+ quickShareAction = null;
+ }
+ }
+
+ /**
+ * Structure returned by the QueryQuickShareInBackgroundTask
+ */
+ static class QuickShareData {
+ public Notification.Action quickShareAction;
+
+ /**
+ * Used to reset the return data on error
+ */
+ public void reset() {
+ quickShareAction = null;
}
}
@@ -155,6 +172,10 @@
void onActionsReady(ScreenshotController.SavedImageData imageData);
}
+ interface QuickShareActionReadyListener {
+ void onActionsReady(ScreenshotController.QuickShareData quickShareData);
+ }
+
// These strings are used for communicating the action invoked to
// ScreenshotNotificationSmartActionsProvider.
static final String EXTRA_ACTION_TYPE = "android:screenshot_action_type";
@@ -519,7 +540,8 @@
mScreenBitmap.setHasAlpha(false);
mScreenBitmap.prepareToDraw();
- saveScreenshotInWorkerThread(finisher, this::showUiOnActionsReady);
+ saveScreenshotInWorkerThread(finisher, this::showUiOnActionsReady,
+ this::showUiOnQuickShareActionReady);
// The window is focusable by default
setWindowFocusable(true);
@@ -664,20 +686,21 @@
saveScreenshotInWorkerThread(
/* onComplete */ finisher,
/* actionsReadyListener */ imageData -> {
- if (DEBUG_CALLBACK) {
- Log.d(TAG, "returning URI to finisher (Consumer<URI>): " + imageData.uri);
- }
- finisher.accept(imageData.uri);
- if (imageData.uri == null) {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED);
- mNotificationsController.notifyScreenshotError(
- R.string.screenshot_failed_to_save_text);
- } else {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED);
- mScreenshotHandler.post(() -> Toast.makeText(mContext,
- R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show());
- }
- });
+ if (DEBUG_CALLBACK) {
+ Log.d(TAG, "returning URI to finisher (Consumer<URI>): " + imageData.uri);
+ }
+ finisher.accept(imageData.uri);
+ if (imageData.uri == null) {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED);
+ mNotificationsController.notifyScreenshotError(
+ R.string.screenshot_failed_to_save_text);
+ } else {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED);
+ mScreenshotHandler.post(() -> Toast.makeText(mContext,
+ R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show());
+ }
+ },
+ null);
}
/**
@@ -718,12 +741,15 @@
* Creates a new worker thread and saves the screenshot to the media store.
*/
private void saveScreenshotInWorkerThread(Consumer<Uri> finisher,
- @Nullable ScreenshotController.ActionsReadyListener actionsReadyListener) {
+ @Nullable ScreenshotController.ActionsReadyListener actionsReadyListener,
+ @Nullable ScreenshotController.QuickShareActionReadyListener
+ quickShareActionsReadyListener) {
ScreenshotController.SaveImageInBackgroundData
data = new ScreenshotController.SaveImageInBackgroundData();
data.image = mScreenBitmap;
data.finisher = finisher;
data.mActionsReadyListener = actionsReadyListener;
+ data.mQuickShareActionsReadyListener = quickShareActionsReadyListener;
if (mSaveInBgTask != null) {
// just log success/failure for the pre-existing screenshot
@@ -786,6 +812,30 @@
}
/**
+ * Sets up the action shade and its entrance animation, once we get the Quick Share action data.
+ */
+ private void showUiOnQuickShareActionReady(ScreenshotController.QuickShareData quickShareData) {
+ if (DEBUG_UI) {
+ Log.d(TAG, "Showing UI for Quick Share action");
+ }
+ if (quickShareData.quickShareAction != null) {
+ mScreenshotHandler.post(() -> {
+ if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) {
+ mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mScreenshotView.addQuickShareChip(quickShareData.quickShareAction);
+ }
+ });
+ } else {
+ mScreenshotView.addQuickShareChip(quickShareData.quickShareAction);
+ }
+ });
+ }
+ }
+
+ /**
* Supplies the necessary bits for the shared element transition to share sheet.
* Note that once supplied, the action intent to share must be sent immediately after.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java
index 9bd7923..99238cd 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java
@@ -60,11 +60,14 @@
CompletableFuture<List<Notification.Action>> getSmartActionsFuture(
String screenshotId, Uri screenshotUri, Bitmap image,
ScreenshotNotificationSmartActionsProvider smartActionsProvider,
+ ScreenshotSmartActionType actionType,
boolean smartActionsEnabled, UserHandle userHandle) {
if (DEBUG_ACTIONS) {
- Log.d(TAG, String.format("getSmartActionsFuture id=%s, uri=%s, provider=%s, "
- + "smartActionsEnabled=%b, userHandle=%s", screenshotId, screenshotUri,
- smartActionsProvider.getClass(), smartActionsEnabled, userHandle));
+ Log.d(TAG, String.format(
+ "getSmartActionsFuture id=%s, uri=%s, provider=%s, actionType=%s, "
+ + "smartActionsEnabled=%b, userHandle=%s",
+ screenshotId, screenshotUri, smartActionsProvider.getClass(), actionType,
+ smartActionsEnabled, userHandle));
}
if (!smartActionsEnabled) {
if (DEBUG_ACTIONS) {
@@ -89,7 +92,7 @@
? runningTask.topActivity
: new ComponentName("", "");
smartActionsFuture = smartActionsProvider.getActions(screenshotId, screenshotUri, image,
- componentName, ScreenshotSmartActionType.REGULAR_SMART_ACTIONS, userHandle);
+ componentName, actionType, userHandle);
} catch (Throwable e) {
long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs;
smartActionsFuture = CompletableFuture.completedFuture(Collections.emptyList());
@@ -107,19 +110,21 @@
@VisibleForTesting
List<Notification.Action> getSmartActions(String screenshotId,
CompletableFuture<List<Notification.Action>> smartActionsFuture, int timeoutMs,
- ScreenshotNotificationSmartActionsProvider smartActionsProvider) {
+ ScreenshotNotificationSmartActionsProvider smartActionsProvider,
+ ScreenshotSmartActionType actionType) {
long startTimeMs = SystemClock.uptimeMillis();
if (DEBUG_ACTIONS) {
- Log.d(TAG, String.format("getSmartActions id=%s, timeoutMs=%d, provider=%s",
- screenshotId, timeoutMs, smartActionsProvider.getClass()));
+ Log.d(TAG,
+ String.format("getSmartActions id=%s, timeoutMs=%d, actionType=%s, provider=%s",
+ screenshotId, timeoutMs, actionType, smartActionsProvider.getClass()));
}
try {
List<Notification.Action> actions = smartActionsFuture.get(timeoutMs,
TimeUnit.MILLISECONDS);
long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs;
if (DEBUG_ACTIONS) {
- Log.d(TAG, String.format("Got %d smart actions. Wait time: %d ms",
- actions.size(), waitTimeMs));
+ Log.d(TAG, String.format("Got %d smart actions. Wait time: %d ms, actionType=%s",
+ actions.size(), waitTimeMs, actionType));
}
notifyScreenshotOp(screenshotId, smartActionsProvider,
ScreenshotNotificationSmartActionsProvider.ScreenshotOp.WAIT_FOR_SMART_ACTIONS,
@@ -129,8 +134,9 @@
} catch (Throwable e) {
long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs;
if (DEBUG_ACTIONS) {
- Log.e(TAG, String.format("Error getting smart actions. Wait time: %d ms",
- waitTimeMs), e);
+ Log.e(TAG, String.format(
+ "Error getting smart actions. Wait time: %d ms, actionType=%s",
+ waitTimeMs, actionType), e);
}
ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus status =
(e instanceof TimeoutException)
@@ -165,7 +171,7 @@
SystemUIFactory.getInstance().createScreenshotNotificationSmartActionsProvider(
context, THREAD_POOL_EXECUTOR, new Handler());
if (DEBUG_ACTIONS) {
- Log.e(TAG, String.format("%s notifyAction: %s id=%s, isSmartAction=%b",
+ Log.d(TAG, String.format("%s notifyAction: %s id=%s, isSmartAction=%b",
provider.getClass(), action, screenshotId, isSmartAction));
}
provider.notifyAction(screenshotId, action, isSmartAction);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index d15f1ff..70b1133 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -137,6 +137,7 @@
private ScreenshotActionChip mShareChip;
private ScreenshotActionChip mEditChip;
private ScreenshotActionChip mScrollChip;
+ private ScreenshotActionChip mQuickShareChip;
private UiEventLogger mUiEventLogger;
private ScreenshotViewCallback mCallbacks;
@@ -151,7 +152,8 @@
private enum PendingInteraction {
PREVIEW,
EDIT,
- SHARE
+ SHARE,
+ QUICK_SHARE
}
public ScreenshotView(Context context) {
@@ -505,6 +507,9 @@
mShareChip.setOnClickListener(v -> {
mShareChip.setIsPending(true);
mEditChip.setIsPending(false);
+ if (mQuickShareChip != null) {
+ mQuickShareChip.setIsPending(false);
+ }
mPendingInteraction = PendingInteraction.SHARE;
});
chips.add(mShareChip);
@@ -514,6 +519,9 @@
mEditChip.setOnClickListener(v -> {
mEditChip.setIsPending(true);
mShareChip.setIsPending(false);
+ if (mQuickShareChip != null) {
+ mQuickShareChip.setIsPending(false);
+ }
mPendingInteraction = PendingInteraction.EDIT;
});
chips.add(mEditChip);
@@ -521,6 +529,9 @@
mScreenshotPreview.setOnClickListener(v -> {
mShareChip.setIsPending(false);
mEditChip.setIsPending(false);
+ if (mQuickShareChip != null) {
+ mQuickShareChip.setIsPending(false);
+ }
mPendingInteraction = PendingInteraction.PREVIEW;
});
@@ -582,6 +593,13 @@
startSharedTransition(
imageData.editTransition.get());
});
+ if (mQuickShareChip != null) {
+ mQuickShareChip.setPendingIntent(imageData.quickShareAction.actionIntent,
+ () -> {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED);
+ animateDismissal();
+ });
+ }
if (mPendingInteraction != null) {
switch (mPendingInteraction) {
@@ -594,6 +612,9 @@
case EDIT:
mEditChip.callOnClick();
break;
+ case QUICK_SHARE:
+ mQuickShareChip.callOnClick();
+ break;
}
} else {
LayoutInflater inflater = LayoutInflater.from(mContext);
@@ -615,6 +636,25 @@
}
}
+ void addQuickShareChip(Notification.Action quickShareAction) {
+ if (mPendingInteraction == null) {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ mQuickShareChip = (ScreenshotActionChip) inflater.inflate(
+ R.layout.global_screenshot_action_chip, mActionsView, false);
+ mQuickShareChip.setText(quickShareAction.title);
+ mQuickShareChip.setIcon(quickShareAction.getIcon(), false);
+ mQuickShareChip.setOnClickListener(v -> {
+ mShareChip.setIsPending(false);
+ mEditChip.setIsPending(false);
+ mQuickShareChip.setIsPending(true);
+ mPendingInteraction = PendingInteraction.QUICK_SHARE;
+ });
+ mQuickShareChip.setAlpha(1);
+ mActionsView.addView(mQuickShareChip);
+ mSmartChips.add(mQuickShareChip);
+ }
+ }
+
boolean isDismissing() {
return (mDismissAnimation != null && mDismissAnimation.isRunning());
}
@@ -700,6 +740,7 @@
mActionsView.removeView(chip);
}
mSmartChips.clear();
+ mQuickShareChip = null;
setAlpha(1);
mDismissButton.setTranslationY(0);
mActionsContainer.setTranslationY(0);
diff --git a/core/java/com/android/internal/colorextraction/drawable/ScrimDrawable.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java
similarity index 77%
rename from core/java/com/android/internal/colorextraction/drawable/ScrimDrawable.java
rename to packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java
index 1fc126e..0a55fbe 100644
--- a/core/java/com/android/internal/colorextraction/drawable/ScrimDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.colorextraction.drawable;
+package com.android.systemui.scrim;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -49,6 +49,7 @@
private float mCornerRadius;
private Rect mBounds;
private ConcaveInfo mConcaveInfo;
+ private int mBottomEdgePosition;
public ScrimDrawable() {
mPaint = new Paint();
@@ -143,21 +144,43 @@
* Make bottom edge concave with provided corner radius
*/
public void setBottomEdgeConcave(float radius) {
+ if (radius == 0) {
+ // Disable clipping completely when there's no radius.
+ mConcaveInfo = null;
+ return;
+ }
// only rounding top corners for clip out path
float[] cornerRadii = new float[]{radius, radius, radius, radius, 0, 0, 0, 0};
mConcaveInfo = new ConcaveInfo(radius, cornerRadii);
}
+ /**
+ * Location of concave edge.
+ * @see #setBottomEdgeConcave(float)
+ */
+ public void setBottomEdgePosition(int y) {
+ if (mBottomEdgePosition == y) {
+ return;
+ }
+ mBottomEdgePosition = y;
+ if (mConcaveInfo == null) {
+ return;
+ }
+ updatePath();
+ invalidateSelf();
+ }
+
@Override
public void draw(@NonNull Canvas canvas) {
mPaint.setColor(mMainColor);
mPaint.setAlpha(mAlpha);
if (mConcaveInfo != null) {
drawConcave(canvas);
+ } else {
+ canvas.drawRoundRect(getBounds().left, getBounds().top, getBounds().right,
+ getBounds().bottom + mCornerRadius,
+ /* x radius*/ mCornerRadius, /* y radius*/ mCornerRadius, mPaint);
}
- canvas.drawRoundRect(getBounds().left, getBounds().top, getBounds().right,
- getBounds().bottom + mCornerRadius,
- /* x radius*/ mCornerRadius, /* y radius*/ mCornerRadius, mPaint);
}
private void drawConcave(Canvas canvas) {
@@ -165,19 +188,23 @@
if (mBounds == null
|| getBounds().right != mBounds.right
|| getBounds().left != mBounds.left) {
- mConcaveInfo.mPath.reset();
- float left = getBounds().left;
- float right = getBounds().right;
- float top = 0f;
- float bottom = mConcaveInfo.mPathOverlap;
- mConcaveInfo.mPath.addRoundRect(left, top, right, bottom,
- mConcaveInfo.mCornerRadii, Path.Direction.CW);
+ mBounds = getBounds();
+ updatePath();
}
- mBounds = getBounds();
- int translation = (int) (mBounds.bottom - mConcaveInfo.mPathOverlap);
- canvas.translate(0, translation);
canvas.clipOutPath(mConcaveInfo.mPath);
- canvas.translate(0, -translation);
+ canvas.drawRect(getBounds().left, getBounds().top, getBounds().right,
+ mBottomEdgePosition + mConcaveInfo.mPathOverlap, mPaint);
+ }
+
+ private void updatePath() {
+ mConcaveInfo.mPath.reset();
+ if (mBounds == null) {
+ mBounds = getBounds();
+ }
+ float top = mBottomEdgePosition;
+ float bottom = mBottomEdgePosition + mConcaveInfo.mPathOverlap;
+ mConcaveInfo.mPath.addRoundRect(mBounds.left, top, mBounds.right, bottom,
+ mConcaveInfo.mCornerRadii, Path.Direction.CW);
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
rename to packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
index a537299..0d9ade6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,10 +11,10 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
-package com.android.systemui.statusbar;
+package com.android.systemui.scrim;
import static java.lang.Float.isNaN;
@@ -38,7 +38,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.systemui.R;
import java.util.concurrent.Executor;
@@ -96,6 +95,9 @@
});
}
+ /**
+ * Needed for WM Shell, which has its own thread structure.
+ */
public void setExecutor(Executor executor, Looper looper) {
mExecutor = executor;
mExecutorLooper = looper;
@@ -108,7 +110,8 @@
}
}
- public void setDrawable(Drawable drawable) {
+ @VisibleForTesting
+ void setDrawable(Drawable drawable) {
executeOnExecutor(() -> {
mDrawable = drawable;
mDrawable.setCallback(this);
@@ -144,16 +147,24 @@
});
}
+ /**
+ * Sets the color of the scrim, without animating them.
+ */
public void setColors(@NonNull ColorExtractor.GradientColors colors) {
setColors(colors, false);
}
+ /**
+ * Sets the scrim colors, optionally animating them.
+ * @param colors The colors.
+ * @param animated If we should animate the transition.
+ */
public void setColors(@NonNull ColorExtractor.GradientColors colors, boolean animated) {
if (colors == null) {
throw new IllegalArgumentException("Colors cannot be null");
}
executeOnExecutor(() -> {
- synchronized(mColorLock) {
+ synchronized (mColorLock) {
if (mColors.equals(colors)) {
return;
}
@@ -168,17 +179,28 @@
return mDrawable;
}
+ /**
+ * Returns current scrim colors.
+ */
public ColorExtractor.GradientColors getColors() {
- synchronized(mColorLock) {
+ synchronized (mColorLock) {
mTmpColors.set(mColors);
}
return mTmpColors;
}
+ /**
+ * Applies tint to this view, without animations.
+ */
public void setTint(int color) {
setTint(color, false);
}
+ /**
+ * Tints this view, optionally animating it.
+ * @param color The color.
+ * @param animated If we should animate.
+ */
public void setTint(int color, boolean animated) {
executeOnExecutor(() -> {
if (mTintColor == color) {
@@ -200,8 +222,8 @@
} else {
boolean hasAlpha = Color.alpha(mTintColor) != 0;
if (hasAlpha) {
- PorterDuff.Mode targetMode = mColorFilter == null ? Mode.SRC_OVER :
- mColorFilter.getMode();
+ PorterDuff.Mode targetMode = mColorFilter == null
+ ? Mode.SRC_OVER : mColorFilter.getMode();
if (mColorFilter == null || mColorFilter.getColor() != mTintColor) {
mColorFilter = new PorterDuffColorFilter(mTintColor, targetMode);
}
@@ -254,6 +276,9 @@
return mViewAlpha;
}
+ /**
+ * Sets a callback that is invoked whenever the alpha, color, or tint change.
+ */
public void setChangeRunnable(Runnable changeRunnable, Executor changeRunnableExecutor) {
mChangeRunnable = changeRunnable;
mChangeRunnableExecutor = changeRunnableExecutor;
@@ -276,9 +301,9 @@
* Make bottom edge concave so overlap between layers is not visible for alphas between 0 and 1
* @return height of concavity
*/
- public float enableBottomEdgeConcave() {
+ public float enableBottomEdgeConcave(boolean clipScrim) {
if (mDrawable instanceof ScrimDrawable) {
- float radius = getResources().getDimensionPixelSize(CORNER_RADIUS);
+ float radius = clipScrim ? getResources().getDimensionPixelSize(CORNER_RADIUS) : 0;
((ScrimDrawable) mDrawable).setBottomEdgeConcave(radius);
return radius;
}
@@ -286,6 +311,16 @@
}
/**
+ * The position of the bottom of the scrim, used for clipping.
+ * @see #enableBottomEdgeConcave(boolean)
+ */
+ public void setBottomEdgePosition(int y) {
+ if (mDrawable instanceof ScrimDrawable) {
+ ((ScrimDrawable) mDrawable).setBottomEdgePosition(y);
+ }
+ }
+
+ /**
* Enable view to have rounded corners with radius of {@link #CORNER_RADIUS}
*/
public void enableRoundedCorners() {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
index 357256c..1ad253e 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
@@ -24,7 +24,9 @@
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
+import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
@@ -64,17 +66,11 @@
private static final Uri BRIGHTNESS_MODE_URI =
Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE);
- private static final Uri BRIGHTNESS_URI =
- Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
- private static final Uri BRIGHTNESS_FLOAT_URI =
- Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FLOAT);
private static final Uri BRIGHTNESS_FOR_VR_FLOAT_URI =
Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT);
- private final float mDefaultBacklight;
private final float mMinimumBacklightForVr;
private final float mMaximumBacklightForVr;
- private final float mDefaultBacklightForVr;
private final int mDisplayId;
private final Context mContext;
@@ -86,6 +82,20 @@
private final Handler mBackgroundHandler;
private final BrightnessObserver mBrightnessObserver;
+ private final DisplayListener mDisplayListener = new DisplayListener() {
+ @Override
+ public void onDisplayAdded(int displayId) {}
+
+ @Override
+ public void onDisplayRemoved(int displayId) {}
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ mBackgroundHandler.post(mUpdateSliderRunnable);
+ notifyCallbacks();
+ }
+ };
+
private ArrayList<BrightnessStateChangeCallback> mChangeCallbacks =
new ArrayList<BrightnessStateChangeCallback>();
@@ -94,6 +104,8 @@
private boolean mListening;
private boolean mExternalChange;
private boolean mControlValueInitialized;
+ private float mBrightnessMin = PowerManager.BRIGHTNESS_MIN;
+ private float mBrightnessMax = PowerManager.BRIGHTNESS_MAX;
private ValueAnimator mSliderAnimator;
@@ -110,28 +122,19 @@
}
@Override
- public void onChange(boolean selfChange) {
- onChange(selfChange, null);
- }
-
- @Override
public void onChange(boolean selfChange, Uri uri) {
if (selfChange) return;
if (BRIGHTNESS_MODE_URI.equals(uri)) {
mBackgroundHandler.post(mUpdateModeRunnable);
mBackgroundHandler.post(mUpdateSliderRunnable);
- } else if (BRIGHTNESS_FLOAT_URI.equals(uri)) {
- mBackgroundHandler.post(mUpdateSliderRunnable);
} else if (BRIGHTNESS_FOR_VR_FLOAT_URI.equals(uri)) {
mBackgroundHandler.post(mUpdateSliderRunnable);
} else {
mBackgroundHandler.post(mUpdateModeRunnable);
mBackgroundHandler.post(mUpdateSliderRunnable);
}
- for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
- cb.onBrightnessLevelChanged();
- }
+ notifyCallbacks();
}
public void startObserving() {
@@ -141,19 +144,16 @@
BRIGHTNESS_MODE_URI,
false, this, UserHandle.USER_ALL);
cr.registerContentObserver(
- BRIGHTNESS_URI,
- false, this, UserHandle.USER_ALL);
- cr.registerContentObserver(
- BRIGHTNESS_FLOAT_URI,
- false, this, UserHandle.USER_ALL);
- cr.registerContentObserver(
BRIGHTNESS_FOR_VR_FLOAT_URI,
false, this, UserHandle.USER_ALL);
+ mDisplayManager.registerDisplayListener(mDisplayListener, mHandler,
+ DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS);
}
public void stopObserving() {
final ContentResolver cr = mContext.getContentResolver();
cr.unregisterContentObserver(this);
+ mDisplayManager.unregisterDisplayListener(mDisplayListener);
}
}
@@ -233,11 +233,15 @@
private final Runnable mUpdateSliderRunnable = new Runnable() {
@Override
public void run() {
- final float valFloat;
final boolean inVrMode = mIsVrModeEnabled;
- valFloat = mDisplayManager.getBrightness(mDisplayId);
+ final BrightnessInfo info = mContext.getDisplay().getBrightnessInfo();
+ if (info == null) {
+ return;
+ }
+ mBrightnessMax = info.brightnessMaximum;
+ mBrightnessMin = info.brightnessMinimum;
// Value is passed as intbits, since this is what the message takes.
- final int valueAsIntBits = Float.floatToIntBits(valFloat);
+ final int valueAsIntBits = Float.floatToIntBits(info.brightness);
mHandler.obtainMessage(MSG_UPDATE_SLIDER, valueAsIntBits,
inVrMode ? 1 : 0).sendToTarget();
}
@@ -295,13 +299,10 @@
mDisplayId = mContext.getDisplayId();
PowerManager pm = context.getSystemService(PowerManager.class);
- mDefaultBacklight = mContext.getDisplay().getBrightnessDefault();
mMinimumBacklightForVr = pm.getBrightnessConstraint(
PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM_VR);
mMaximumBacklightForVr = pm.getBrightnessConstraint(
PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM_VR);
- mDefaultBacklightForVr = pm.getBrightnessConstraint(
- PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT_VR);
mDisplayManager = context.getSystemService(DisplayManager.class);
mVrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
@@ -337,7 +338,6 @@
final float minBacklight;
final float maxBacklight;
final int metric;
- final String settingToChange;
if (mIsVrModeEnabled) {
metric = MetricsEvent.ACTION_BRIGHTNESS_FOR_VR;
@@ -347,12 +347,12 @@
metric = mAutomatic
? MetricsEvent.ACTION_BRIGHTNESS_AUTO
: MetricsEvent.ACTION_BRIGHTNESS;
- minBacklight = PowerManager.BRIGHTNESS_MIN;
- maxBacklight = PowerManager.BRIGHTNESS_MAX;
+ minBacklight = mBrightnessMin;
+ maxBacklight = mBrightnessMax;
}
- final float valFloat = MathUtils.min(convertGammaToLinearFloat(value,
- minBacklight, maxBacklight),
- 1.0f);
+ final float valFloat = MathUtils.min(
+ convertGammaToLinearFloat(value, minBacklight, maxBacklight),
+ maxBacklight);
if (stopTracking) {
// TODO(brightnessfloat): change to use float value instead.
MetricsLogger.action(mContext, metric,
@@ -403,8 +403,8 @@
min = mMinimumBacklightForVr;
max = mMaximumBacklightForVr;
} else {
- min = PowerManager.BRIGHTNESS_MIN;
- max = PowerManager.BRIGHTNESS_MAX;
+ min = mBrightnessMin;
+ max = mBrightnessMax;
}
// convertGammaToLinearFloat returns 0-1
if (BrightnessSynchronizer.floatEquals(brightnessValue,
@@ -439,6 +439,13 @@
mSliderAnimator.start();
}
+ private void notifyCallbacks() {
+ final int size = mChangeCallbacks.size();
+ for (int i = 0; i < size; i++) {
+ mChangeCallbacks.get(i).onBrightnessLevelChanged();
+ }
+ }
+
/** Factory for creating a {@link BrightnessController}. */
public static class Factory {
private final Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 2a46893..e8ce5f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -98,15 +98,6 @@
var globalActionsSpring = DepthAnimation()
var showingHomeControls: Boolean = false
- @VisibleForTesting
- var brightnessMirrorSpring = DepthAnimation()
- var brightnessMirrorVisible: Boolean = false
- set(value) {
- field = value
- brightnessMirrorSpring.animateTo(if (value) blurUtils.blurRadiusOfRatio(1f)
- else 0)
- }
-
var qsPanelExpansion = 0f
set(value) {
if (field == value) return
@@ -169,7 +160,6 @@
normalizedBlurRadius * ANIMATION_BLUR_FRACTION).toInt()
combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsPanelExpansion))
var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius).toFloat()
- shadeRadius *= 1f - brightnessMirrorSpring.ratio
val launchProgress = notificationLaunchAnimationParams?.linearProgress ?: 0f
shadeRadius *= (1f - launchProgress) * (1f - launchProgress)
@@ -263,7 +253,6 @@
shadeSpring.finishIfRunning()
shadeAnimation.finishIfRunning()
globalActionsSpring.finishIfRunning()
- brightnessMirrorSpring.finishIfRunning()
}
}
@@ -425,7 +414,6 @@
it.println("shadeRadius: ${shadeSpring.radius}")
it.println("shadeAnimation: ${shadeAnimation.radius}")
it.println("globalActionsRadius: ${globalActionsSpring.radius}")
- it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}")
it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
it.println("notificationLaunchAnimationProgress: " +
"${notificationLaunchAnimationParams?.linearProgress}")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index f4266a2..fb109f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -84,7 +84,6 @@
private int mCutoutHeight;
private int mGapHeight;
private int mIndexOfFirstViewInShelf = -1;
- private int mIndexOfFirstViewInOverflowingSection = -1;
private NotificationShelfController mController;
@@ -180,7 +179,6 @@
viewState.xTranslation = getTranslationX();
viewState.hasItemsInStableShelf = lastViewState.inShelf;
viewState.firstViewInShelf = algorithmState.firstViewInShelf;
- viewState.firstViewInOverflowSection = algorithmState.firstViewInOverflowSection;
if (mNotGoneIndex != -1) {
viewState.notGoneIndex = Math.min(viewState.notGoneIndex, mNotGoneIndex);
}
@@ -268,17 +266,6 @@
// TODO(b/172289889) scale mPaddingBetweenElements with expansion amount
if ((isLastChild && !child.isInShelf()) || aboveShelf || backgroundForceHidden) {
notificationClipEnd = stackEnd;
- } else if (mAmbientState.isExpansionChanging()) {
- if (mIndexOfFirstViewInOverflowingSection != -1
- && i >= mIndexOfFirstViewInOverflowingSection) {
- // Clip notifications in (section overflowing into shelf) to shelf start.
- notificationClipEnd = shelfStart - mPaddingBetweenElements;
- } else {
- // Clip notifications before the section overflowing into shelf
- // to stackEnd because we do not show the shelf if the section right before the
- // shelf is still hidden.
- notificationClipEnd = stackEnd;
- }
} else {
notificationClipEnd = shelfStart - mPaddingBetweenElements;
}
@@ -692,7 +679,6 @@
private void setHideBackground(boolean hideBackground) {
if (mHideBackground != hideBackground) {
mHideBackground = hideBackground;
- updateBackground();
updateOutline();
}
}
@@ -702,10 +688,6 @@
return !mHideBackground && super.needsOutline();
}
- @Override
- protected boolean shouldHideBackground() {
- return super.shouldHideBackground() || mHideBackground;
- }
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
@@ -836,11 +818,6 @@
mIndexOfFirstViewInShelf = mHostLayoutController.indexOfChild(firstViewInShelf);
}
- public void setFirstViewInOverflowingSection(ExpandableView firstViewInOverflowingSection) {
- mIndexOfFirstViewInOverflowingSection =
- mHostLayoutController.indexOfChild(firstViewInOverflowingSection);
- }
-
private class ShelfState extends ExpandableViewState {
private boolean hasItemsInStableShelf;
private ExpandableView firstViewInShelf;
@@ -854,7 +831,6 @@
super.applyToView(view);
setIndexOfFirstViewInShelf(firstViewInShelf);
- setFirstViewInOverflowingSection(firstViewInOverflowSection);
updateAppearance();
setHasItemsInStableShelf(hasItemsInStableShelf);
mShelfIcons.setAnimationsEnabled(mAnimationsEnabled);
@@ -868,7 +844,6 @@
super.animateTo(child, properties);
setIndexOfFirstViewInShelf(firstViewInShelf);
- setFirstViewInOverflowingSection(firstViewInOverflowSection);
updateAppearance();
setHasItemsInStableShelf(hasItemsInStableShelf);
mShelfIcons.setAnimationsEnabled(mAnimationsEnabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
index 46a971b..1e07131 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
@@ -68,7 +68,7 @@
}
private fun isImmersiveIndicatorEnabled(): Boolean {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_ENABLE_IMMERSIVE_INDICATOR, false)
+ PROPERTY_ENABLE_IMMERSIVE_INDICATOR, true)
}
/** True from the time a scheduled event starts until it's animation finishes */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index d925a93..c85b62f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -84,14 +84,6 @@
notificationShadeWindowViewController.setExpandAnimationRunning(false)
}
- override fun onLaunchAnimationTimedOut() {
- notificationShadeWindowViewController.setExpandAnimationRunning(false)
- }
-
- override fun onLaunchAnimationAborted() {
- notificationShadeWindowViewController.setExpandAnimationRunning(false)
- }
-
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
notification.isExpandAnimationRunning = true
notificationListContainer.setExpandingNotification(notification)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index fb42c42..fad0e49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection
+import android.app.Notification
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.NotificationManager.IMPORTANCE_MIN
import android.service.notification.NotificationListenerService.Ranking
@@ -25,6 +26,7 @@
import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger
import com.android.systemui.statusbar.notification.NotificationFilter
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
@@ -33,11 +35,11 @@
import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
import com.android.systemui.statusbar.notification.stack.PriorityBucket
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
import com.android.systemui.statusbar.policy.HeadsUpManager
import dagger.Lazy
import java.util.Objects
import javax.inject.Inject
+import kotlin.Comparator
private const val TAG = "NotifRankingManager"
@@ -77,6 +79,9 @@
val aIsFsn = a.isColorizedForegroundService()
val bIsFsn = b.isColorizedForegroundService()
+ val aCall = a.isImportantCall()
+ val bCall = b.isImportantCall()
+
val aPersonType = a.getPeopleNotificationType()
val bPersonType = b.getPeopleNotificationType()
@@ -96,6 +101,7 @@
// Provide consistent ranking with headsUpManager
aHeadsUp -> headsUpManager.compare(a, b)
aIsFsn != bIsFsn -> if (aIsFsn) -1 else 1
+ aCall != bCall -> if (aCall) -1 else 1
usePeopleFiltering && aPersonType != bPersonType ->
peopleNotificationIdentifier.compareTo(aPersonType, bPersonType)
// Upsort current media notification.
@@ -150,11 +156,12 @@
@PriorityBucket
private fun getBucketForEntry(entry: NotificationEntry): Int {
+ val isImportantCall = entry.isImportantCall()
val isHeadsUp = entry.isRowHeadsUp
val isMedia = entry.isImportantMedia()
val isSystemMax = entry.isSystemMax()
return when {
- entry.isColorizedForegroundService() -> BUCKET_FOREGROUND_SERVICE
+ entry.isColorizedForegroundService() || isImportantCall -> BUCKET_FOREGROUND_SERVICE
usePeopleFiltering && entry.isConversation() -> BUCKET_PEOPLE
isHeadsUp || isMedia || isSystemMax || entry.isHighPriority() -> BUCKET_ALERTING
else -> BUCKET_SILENT
@@ -186,7 +193,7 @@
}
private fun NotificationEntry.isImportantMedia() =
- key == mediaManager.mediaNotificationKey && ranking.importance > IMPORTANCE_MIN
+ key == mediaManager.mediaNotificationKey && importance > IMPORTANCE_MIN
private fun NotificationEntry.isConversation() = getPeopleNotificationType() != TYPE_NON_PERSON
@@ -204,6 +211,10 @@
private fun StatusBarNotification.isSystemNotification() =
"android" == packageName || "com.android.systemui" == packageName
+private fun NotificationEntry.isImportantCall() =
+ sbn.notification.extras?.getString(Notification.EXTRA_TEMPLATE) ==
+ "android.app.Notification\$CallStyle" && importance > IMPORTANCE_MIN
+
private fun NotificationEntry.isColorizedForegroundService() = sbn.notification.run {
isForegroundService && isColorized && importance > IMPORTANCE_MIN
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index f8543f7..b237f6f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -22,13 +22,11 @@
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewAnimationUtils;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
@@ -50,9 +48,6 @@
*/
public abstract class ActivatableNotificationView extends ExpandableOutlineView {
- private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220;
- private static final int ACTIVATE_ANIMATION_LENGTH = 220;
-
/**
* The amount of width, which is kept in the end when performing a disappear animation (also
* the amount from which the horizontal appearing begins)
@@ -97,8 +92,6 @@
private int mNormalRippleColor;
private Gefingerpoken mTouchHandler;
- private boolean mDimmed;
-
int mBgTint = NO_COLOR;
/**
@@ -115,7 +108,6 @@
private Interpolator mCurrentAlphaInterpolator;
NotificationBackgroundView mBackgroundNormal;
- private NotificationBackgroundView mBackgroundDimmed;
private ObjectAnimator mBackgroundAnimator;
private RectF mAppearAnimationRect = new RectF();
private float mAnimationTranslationY;
@@ -129,13 +121,11 @@
private long mLastActionUpTime;
private float mNormalBackgroundVisibilityAmount;
- private float mDimmedBackgroundFadeInAmount = -1;
private ValueAnimator.AnimatorUpdateListener mBackgroundVisibilityUpdater
= new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
setNormalBackgroundVisibilityAmount(mBackgroundNormal.getAlpha());
- mDimmedBackgroundFadeInAmount = mBackgroundDimmed.getAlpha();
}
};
private FakeShadowView mFakeShadow;
@@ -145,18 +135,12 @@
private int mOverrideTint;
private float mOverrideAmount;
private boolean mShadowHidden;
- /**
- * Similar to mDimmed but is also true if it's not dimmable but should be
- */
- private boolean mNeedsDimming;
- private int mDimmedAlpha;
private boolean mIsHeadsUpAnimation;
private int mHeadsUpAddStartLocation;
private float mHeadsUpLocation;
private boolean mIsAppearing;
private boolean mDismissed;
private boolean mRefocusOnDismiss;
- private OnDimmedListener mOnDimmedListener;
private AccessibilityManager mAccessibilityManager;
public ActivatableNotificationView(Context context, AttributeSet attrs) {
@@ -176,8 +160,6 @@
R.color.notification_ripple_tinted_color);
mNormalRippleColor = mContext.getColor(
R.color.notification_ripple_untinted_color);
- mDimmedAlpha = Color.alpha(mContext.getColor(
- R.color.notification_background_dimmed_color));
}
private void initDimens() {
@@ -206,21 +188,18 @@
mBackgroundNormal = findViewById(R.id.backgroundNormal);
mFakeShadow = findViewById(R.id.fake_shadow);
mShadowHidden = mFakeShadow.getVisibility() != VISIBLE;
- mBackgroundDimmed = findViewById(R.id.backgroundDimmed);
initBackground();
- updateBackground();
updateBackgroundTint();
updateOutlineAlpha();
}
/**
- * Sets the custom backgrounds on {@link #mBackgroundNormal} and {@link #mBackgroundDimmed}.
+ * Sets the custom background on {@link #mBackgroundNormal}
* This method can also be used to reload the backgrounds on both of those views, which can
* be useful in a configuration change.
*/
protected void initBackground() {
mBackgroundNormal.setCustomBackground(R.drawable.notification_material_bg);
- mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim);
}
@@ -264,20 +243,9 @@
}
@Override
- public void drawableHotspotChanged(float x, float y) {
- if (!mDimmed){
- mBackgroundNormal.drawableHotspotChanged(x, y);
- }
- }
-
- @Override
protected void drawableStateChanged() {
super.drawableStateChanged();
- if (mDimmed) {
- mBackgroundDimmed.setState(getDrawableState());
- } else {
- mBackgroundNormal.setState(getDrawableState());
- }
+ mBackgroundNormal.setState(getDrawableState());
}
void setRippleAllowed(boolean allowed) {
@@ -285,7 +253,6 @@
}
void makeActive() {
- startActivateAnimation(false /* reverse */);
mActivated = true;
if (mOnActivatedListener != null) {
mOnActivatedListener.onActivated(this);
@@ -296,106 +263,18 @@
return mActivated;
}
- private void startActivateAnimation(final boolean reverse) {
- if (!isAttachedToWindow()) {
- return;
- }
- if (!isDimmable()) {
- return;
- }
- int widthHalf = mBackgroundNormal.getWidth()/2;
- int heightHalf = mBackgroundNormal.getActualHeight()/2;
- float radius = (float) Math.sqrt(widthHalf*widthHalf + heightHalf*heightHalf);
- Animator animator;
- if (reverse) {
- animator = ViewAnimationUtils.createCircularReveal(mBackgroundNormal,
- widthHalf, heightHalf, radius, 0);
- } else {
- animator = ViewAnimationUtils.createCircularReveal(mBackgroundNormal,
- widthHalf, heightHalf, 0, radius);
- }
- mBackgroundNormal.setVisibility(View.VISIBLE);
- Interpolator interpolator;
- Interpolator alphaInterpolator;
- if (!reverse) {
- interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
- alphaInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
- } else {
- interpolator = ACTIVATE_INVERSE_INTERPOLATOR;
- alphaInterpolator = ACTIVATE_INVERSE_ALPHA_INTERPOLATOR;
- }
- animator.setInterpolator(interpolator);
- animator.setDuration(ACTIVATE_ANIMATION_LENGTH);
- if (reverse) {
- mBackgroundNormal.setAlpha(1f);
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- updateBackground();
- }
- });
- animator.start();
- } else {
- mBackgroundNormal.setAlpha(0.4f);
- animator.start();
- }
- mBackgroundNormal.animate()
- .alpha(reverse ? 0f : 1f)
- .setInterpolator(alphaInterpolator)
- .setUpdateListener(animation -> {
- float animatedFraction = animation.getAnimatedFraction();
- if (reverse) {
- animatedFraction = 1.0f - animatedFraction;
- }
- setNormalBackgroundVisibilityAmount(animatedFraction);
- })
- .setDuration(ACTIVATE_ANIMATION_LENGTH);
- }
-
/**
* Cancels the hotspot and makes the notification inactive.
*/
public void makeInactive(boolean animate) {
if (mActivated) {
mActivated = false;
- if (mDimmed) {
- if (animate) {
- startActivateAnimation(true /* reverse */);
- } else {
- updateBackground();
- }
- }
}
if (mOnActivatedListener != null) {
mOnActivatedListener.onActivationReset(this);
}
}
- public void setDimmed(boolean dimmed, boolean fade) {
- mNeedsDimming = dimmed;
- if (mOnDimmedListener != null) {
- mOnDimmedListener.onSetDimmed(dimmed);
- }
- dimmed &= isDimmable();
- if (mDimmed != dimmed) {
- mDimmed = dimmed;
- resetBackgroundAlpha();
- if (fade) {
- fadeDimmedBackground();
- } else {
- updateBackground();
- }
- }
- }
-
- public boolean isDimmable() {
- return true;
- }
-
- public boolean isDimmed() {
- return mDimmed;
- }
-
private void updateOutlineAlpha() {
float alpha = NotificationStackScrollLayout.BACKGROUND_ALPHA_DIMMED;
alpha = (alpha + (1.0f - alpha) * mNormalBackgroundVisibilityAmount);
@@ -448,7 +327,6 @@
public void setDistanceToTopRoundness(float distanceToTopRoundness) {
super.setDistanceToTopRoundness(distanceToTopRoundness);
mBackgroundNormal.setDistanceToTopRoundness(distanceToTopRoundness);
- mBackgroundDimmed.setDistanceToTopRoundness(distanceToTopRoundness);
}
/** Sets whether this view is the last notification in a section. */
@@ -457,7 +335,6 @@
if (lastInSection != mLastInSection) {
super.setLastInSection(lastInSection);
mBackgroundNormal.setLastInSection(lastInSection);
- mBackgroundDimmed.setLastInSection(lastInSection);
}
}
@@ -467,7 +344,6 @@
if (firstInSection != mFirstInSection) {
super.setFirstInSection(firstInSection);
mBackgroundNormal.setFirstInSection(firstInSection);
- mBackgroundDimmed.setFirstInSection(firstInSection);
}
}
@@ -486,13 +362,6 @@
mOverrideAmount = overrideAmount;
int newColor = calculateBgColor();
setBackgroundTintColor(newColor);
- if (!isDimmable() && mNeedsDimming) {
- mBackgroundNormal.setDrawableAlpha((int) NotificationUtils.interpolate(255,
- mDimmedAlpha,
- overrideAmount));
- } else {
- mBackgroundNormal.setDrawableAlpha(255);
- }
}
protected void updateBackgroundTint() {
@@ -504,7 +373,6 @@
mBackgroundColorAnimator.cancel();
}
int rippleColor = getRippleColor();
- mBackgroundDimmed.setRippleColor(rippleColor);
mBackgroundNormal.setRippleColor(rippleColor);
int color = calculateBgColor();
if (!animated) {
@@ -537,110 +405,12 @@
// We don't need to tint a normal notification
color = 0;
}
- mBackgroundDimmed.setTint(color);
mBackgroundNormal.setTint(color);
}
}
- /**
- * Fades the background when the dimmed state changes.
- */
- private void fadeDimmedBackground() {
- mBackgroundDimmed.animate().cancel();
- mBackgroundNormal.animate().cancel();
- if (mActivated) {
- updateBackground();
- return;
- }
- if (!shouldHideBackground()) {
- if (mDimmed) {
- mBackgroundDimmed.setVisibility(View.VISIBLE);
- } else {
- mBackgroundNormal.setVisibility(View.VISIBLE);
- }
- }
- float startAlpha = mDimmed ? 1f : 0;
- float endAlpha = mDimmed ? 0 : 1f;
- int duration = BACKGROUND_ANIMATION_LENGTH_MS;
- // Check whether there is already a background animation running.
- if (mBackgroundAnimator != null) {
- startAlpha = (Float) mBackgroundAnimator.getAnimatedValue();
- duration = (int) mBackgroundAnimator.getCurrentPlayTime();
- mBackgroundAnimator.removeAllListeners();
- mBackgroundAnimator.cancel();
- if (duration <= 0) {
- updateBackground();
- return;
- }
- }
- mBackgroundNormal.setAlpha(startAlpha);
- mBackgroundAnimator =
- ObjectAnimator.ofFloat(mBackgroundNormal, View.ALPHA, startAlpha, endAlpha);
- mBackgroundAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- mBackgroundAnimator.setDuration(duration);
- mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- updateBackground();
- mBackgroundAnimator = null;
- mDimmedBackgroundFadeInAmount = -1;
- }
- });
- mBackgroundAnimator.addUpdateListener(mBackgroundVisibilityUpdater);
- mBackgroundAnimator.start();
- }
-
- protected void updateBackgroundAlpha(float transformationAmount) {
- float bgAlpha = isChildInGroup() && mDimmed ? transformationAmount : 1f;
- if (mDimmedBackgroundFadeInAmount != -1) {
- bgAlpha *= mDimmedBackgroundFadeInAmount;
- }
- mBackgroundDimmed.setAlpha(bgAlpha);
- }
-
- protected void resetBackgroundAlpha() {
- updateBackgroundAlpha(0f /* transformationAmount */);
- }
-
- protected void updateBackground() {
- cancelFadeAnimations();
- if (shouldHideBackground()) {
- mBackgroundDimmed.setVisibility(INVISIBLE);
- mBackgroundNormal.setVisibility(mActivated ? VISIBLE : INVISIBLE);
- } else if (mDimmed) {
- // When groups are animating to the expanded state from the lockscreen, show the
- // normal background instead of the dimmed background.
- final boolean dontShowDimmed = isGroupExpansionChanging() && isChildInGroup();
- mBackgroundDimmed.setVisibility(dontShowDimmed ? View.INVISIBLE : View.VISIBLE);
- mBackgroundNormal.setVisibility((mActivated || dontShowDimmed)
- ? View.VISIBLE
- : View.INVISIBLE);
- } else {
- mBackgroundDimmed.setVisibility(View.INVISIBLE);
- mBackgroundNormal.setVisibility(View.VISIBLE);
- mBackgroundNormal.setAlpha(1f);
- // make in inactive to avoid it sticking around active
- makeInactive(false /* animate */);
- }
- setNormalBackgroundVisibilityAmount(
- mBackgroundNormal.getVisibility() == View.VISIBLE ? 1.0f : 0.0f);
- }
-
protected void updateBackgroundClipping() {
mBackgroundNormal.setBottomAmountClips(!isChildInGroup());
- mBackgroundDimmed.setBottomAmountClips(!isChildInGroup());
- }
-
- protected boolean shouldHideBackground() {
- return false;
- }
-
- private void cancelFadeAnimations() {
- if (mBackgroundAnimator != null) {
- mBackgroundAnimator.cancel();
- }
- mBackgroundDimmed.animate().cancel();
- mBackgroundNormal.animate().cancel();
}
@Override
@@ -654,21 +424,18 @@
super.setActualHeight(actualHeight, notifyListeners);
setPivotY(actualHeight / 2);
mBackgroundNormal.setActualHeight(actualHeight);
- mBackgroundDimmed.setActualHeight(actualHeight);
}
@Override
public void setClipTopAmount(int clipTopAmount) {
super.setClipTopAmount(clipTopAmount);
mBackgroundNormal.setClipTopAmount(clipTopAmount);
- mBackgroundDimmed.setClipTopAmount(clipTopAmount);
}
@Override
public void setClipBottomAmount(int clipBottomAmount) {
super.setClipBottomAmount(clipBottomAmount);
mBackgroundNormal.setClipBottomAmount(clipBottomAmount);
- mBackgroundDimmed.setClipBottomAmount(clipBottomAmount);
}
@Override
@@ -891,13 +658,11 @@
}
private void applyBackgroundRoundness(float topRadius, float bottomRadius) {
- mBackgroundDimmed.setRadius(topRadius, bottomRadius);
mBackgroundNormal.setRadius(topRadius, bottomRadius);
}
@Override
protected void setBackgroundTop(int backgroundTop) {
- mBackgroundDimmed.setBackgroundTop(backgroundTop);
mBackgroundNormal.setBackgroundTop(backgroundTop);
}
@@ -1033,10 +798,6 @@
mTouchHandler = touchHandler;
}
- void setOnDimmedListener(OnDimmedListener onDimmedListener) {
- mOnDimmedListener = onDimmedListener;
- }
-
public void setAccessibilityManager(AccessibilityManager accessibilityManager) {
mAccessibilityManager = accessibilityManager;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
index edd97af..0a63e19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
@@ -85,7 +85,6 @@
mExpandableOutlineViewController.init();
mView.setOnTouchListener(mTouchHandler);
mView.setTouchHandler(mTouchHandler);
- mView.setOnDimmedListener(dimmed -> mNeedsDimming = dimmed);
mView.setAccessibilityManager(mAccessibilityManager);
}
@@ -116,14 +115,8 @@
if (mAccessibilityManager.isTouchExplorationEnabled()) {
return false;
}
- if (mNeedsDimming && mView.isInteractive()) {
- if (mNeedsDimming && !mView.isDimmed()) {
- // We're actually dimmed, but our content isn't dimmable,
- // let's ensure we have a ripple
- return false;
- }
- result = mNotificationTapHelper.onTouchEvent(ev, mView.getActualHeight());
- } else if (ev.getAction() == MotionEvent.ACTION_UP) {
+
+ if (ev.getAction() == MotionEvent.ACTION_UP) {
// If this is a false tap, capture the even so it doesn't result in a click.
return mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY);
}
@@ -132,17 +125,6 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (mNeedsDimming && ev.getActionMasked() == MotionEvent.ACTION_DOWN
- && mView.disallowSingleClick(ev)
- && !mAccessibilityManager.isTouchExplorationEnabled()) {
- if (!mView.isActive()) {
- return true;
- } else if (mFalsingManager.isFalseDoubleTap()) {
- mBlockNextTouch = true;
- mView.makeInactive(true /* animate */);
- return true;
- }
- }
return false;
}
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 d21af11..b5d2ea5 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
@@ -630,17 +630,6 @@
mSecureStateProvider = secureStateProvider;
}
- @Override
- public boolean isDimmable() {
- if (!getShowingLayout().isDimmable()) {
- return false;
- }
- if (showingPulsing()) {
- return false;
- }
- return super.isDimmable();
- }
-
private void updateLimits() {
for (NotificationContentView l : mLayouts) {
updateLimitsForView(l);
@@ -853,7 +842,6 @@
mNotificationParent = isChildInGroup ? parent : null;
mPrivateLayout.setIsChildInGroup(isChildInGroup);
- resetBackgroundAlpha();
updateBackgroundForGroupState();
updateClickAndFocus();
if (mNotificationParent != null) {
@@ -895,11 +883,6 @@
}
@Override
- protected boolean shouldHideBackground() {
- return super.shouldHideBackground() || mShowNoBackground;
- }
-
- @Override
public boolean isSummaryWithChildren() {
return mIsSummaryWithChildren;
}
@@ -2873,7 +2856,6 @@
mShowNoBackground = false;
}
updateOutline();
- updateBackground();
}
public int getPositionOfChild(ExpandableNotificationRow childRow) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
index 9e70f0a..caba3ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
@@ -37,8 +37,9 @@
private ImageView mConversationIconView;
private TextView mConversationSenderName;
private View mConversationFacePile;
- private int mConversationIconSize;
+ private int mSingleAvatarSize;
private int mFacePileSize;
+ private int mFacePileAvatarSize;
private int mFacePileProtectionWidth;
public HybridConversationNotificationView(Context context) {
@@ -67,7 +68,9 @@
mConversationSenderName = requireViewById(R.id.conversation_notification_sender);
mFacePileSize = getResources()
.getDimensionPixelSize(R.dimen.conversation_single_line_face_pile_size);
- mConversationIconSize = getResources()
+ mFacePileAvatarSize = getResources()
+ .getDimensionPixelSize(R.dimen.conversation_single_line_face_pile_avatar_size);
+ mSingleAvatarSize = getResources()
.getDimensionPixelSize(R.dimen.conversation_single_line_avatar_size);
mFacePileProtectionWidth = getResources().getDimensionPixelSize(
R.dimen.conversation_single_line_face_pile_protection_width);
@@ -89,6 +92,7 @@
mConversationFacePile.setVisibility(GONE);
mConversationIconView.setVisibility(VISIBLE);
mConversationIconView.setImageIcon(conversationIcon);
+ setSize(mConversationIconView, mSingleAvatarSize);
} else {
// If there isn't an icon, generate a "face pile" based on the sender avatars
mConversationIconView.setVisibility(GONE);
@@ -104,9 +108,9 @@
com.android.internal.R.id.conversation_face_pile_top);
conversationLayout.bindFacePile(facePileBottomBg, facePileBottom, facePileTop);
setSize(mConversationFacePile, mFacePileSize);
- setSize(facePileBottom, mConversationIconSize);
- setSize(facePileTop, mConversationIconSize);
- setSize(facePileBottomBg, mConversationIconSize + 2 * mFacePileProtectionWidth);
+ setSize(facePileBottom, mFacePileAvatarSize);
+ setSize(facePileTop, mFacePileAvatarSize);
+ setSize(facePileBottomBg, mFacePileAvatarSize + 2 * mFacePileProtectionWidth);
mTransformationHelper.addViewTransformingToSimilar(facePileTop);
mTransformationHelper.addViewTransformingToSimilar(facePileBottom);
mTransformationHelper.addViewTransformingToSimilar(facePileBottomBg);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index a90e76b..fe4ea28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -693,7 +693,6 @@
endColor = NotificationUtils.interpolateColors(startColor, endColor,
transformationAmount);
}
- mContainingNotification.updateBackgroundAlpha(transformationAmount);
mContainingNotification.setContentBackground(endColor, false, this);
}
@@ -868,7 +867,6 @@
public void updateBackgroundColor(boolean animate) {
int customBackgroundColor = getBackgroundColor(mVisibleType);
- mContainingNotification.resetBackgroundAlpha();
mContainingNotification.setContentBackground(customBackgroundColor, animate, this);
}
@@ -1260,7 +1258,7 @@
RemoteInputView riv = RemoteInputView.inflate(
mContext, actionContainer, entry, mRemoteInputController);
- riv.setVisibility(View.INVISIBLE);
+ riv.setVisibility(View.GONE);
actionContainer.addView(riv, new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index 15ca24e..8ee9134 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -20,14 +20,12 @@
import android.app.Notification;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.util.ArraySet;
import android.util.Pair;
import android.view.NotificationHeaderView;
import android.view.NotificationTopLineView;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewGroup.MarginLayoutParams;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.widget.ImageButton;
@@ -168,53 +166,6 @@
}
}
- public void applyConversationSkin() {
- if (mAppNameText != null) {
- final ColorStateList colors = mAppNameText.getTextColors();
- mAppNameText.setTextAppearance(
- com.android.internal.R.style
- .TextAppearance_DeviceDefault_Notification_Conversation_AppName);
- mAppNameText.setTextColor(colors);
- MarginLayoutParams layoutParams = (MarginLayoutParams) mAppNameText.getLayoutParams();
- layoutParams.setMarginStart(0);
- }
- if (mNotificationTopLine != null) {
- int paddingStart = mNotificationTopLine.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.conversation_content_start);
- mNotificationTopLine.setPaddingStart(paddingStart);
- }
- if (mIcon != null) {
- MarginLayoutParams layoutParams = (MarginLayoutParams) mIcon.getLayoutParams();
- int marginStart = mIcon.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.conversation_icon_circle_start);
- layoutParams.setMarginStart(marginStart);
- }
- }
-
- public void clearConversationSkin() {
- if (mAppNameText != null) {
- final ColorStateList colors = mAppNameText.getTextColors();
- mAppNameText.setTextAppearance(
- com.android.internal.R.style.TextAppearance_DeviceDefault_Notification_Info);
- mAppNameText.setTextColor(colors);
- MarginLayoutParams layoutParams = (MarginLayoutParams) mAppNameText.getLayoutParams();
- final int marginStart = mAppNameText.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_header_app_name_margin_start);
- layoutParams.setMarginStart(marginStart);
- }
- if (mNotificationTopLine != null) {
- int paddingStart = mNotificationTopLine.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_content_margin_start);
- mNotificationTopLine.setPaddingStart(paddingStart);
- }
- if (mIcon != null) {
- MarginLayoutParams layoutParams = (MarginLayoutParams) mIcon.getLayoutParams();
- int marginStart = mIcon.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_icon_circle_start);
- layoutParams.setMarginStart(marginStart);
- }
- }
-
/**
* Adds the remaining TransformTypes to the TransformHelper. This is done to make sure that each
* child is faded automatically and doesn't have to be manually added.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaHeaderView.java
index 040f707..0247a99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaHeaderView.java
@@ -19,7 +19,6 @@
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.util.AttributeSet;
-import android.view.ViewGroup;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -43,11 +42,4 @@
public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear) {
// No animation, it doesn't need it, this would be local
}
-
- public void setContentView(ViewGroup contentView) {
- addView(contentView);
- ViewGroup.LayoutParams layoutParams = contentView.getLayoutParams();
- layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
- layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 5f3933b..99fe541 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -43,7 +43,6 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.HybridGroupManager;
import com.android.systemui.statusbar.notification.row.HybridNotificationView;
-import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import java.util.ArrayList;
@@ -336,15 +335,6 @@
}
mNotificationHeaderWrapper.setExpanded(mChildrenExpanded);
mNotificationHeaderWrapper.onContentUpdated(mContainingNotification);
- if (mNotificationHeaderWrapper instanceof NotificationHeaderViewWrapper) {
- NotificationHeaderViewWrapper headerWrapper =
- (NotificationHeaderViewWrapper) mNotificationHeaderWrapper;
- if (isConversation) {
- headerWrapper.applyConversationSkin();
- } else {
- headerWrapper.clearConversationSkin();
- }
- }
recreateLowPriorityHeader(builder, isConversation);
updateHeaderVisibility(false /* animate */);
updateChildrenAppearance();
@@ -378,15 +368,6 @@
header.reapply(getContext(), mNotificationHeaderLowPriority);
}
mNotificationHeaderWrapperLowPriority.onContentUpdated(mContainingNotification);
- if (mNotificationHeaderWrapper instanceof NotificationHeaderViewWrapper) {
- NotificationHeaderViewWrapper headerWrapper =
- (NotificationHeaderViewWrapper) mNotificationHeaderWrapper;
- if (isConversation) {
- headerWrapper.applyConversationSkin();
- } else {
- headerWrapper.clearConversationSkin();
- }
- }
resetHeaderVisibilityIfNeeded(mNotificationHeaderLowPriority, calculateDesiredHeader());
} else {
removeView(mNotificationHeaderLowPriority);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index b06f7d2..45ce20a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -138,7 +138,7 @@
incomingHeaderController.reinflateView(parent)
mediaControlsView =
reinflateView(mediaControlsView, layoutInflater, R.layout.keyguard_media_header)
- .also(keyguardMediaController::attach)
+ keyguardMediaController.attachSinglePaneContainer(mediaControlsView)
}
override fun beginsSection(view: View, previous: View?): Boolean =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 4fc49ed..527443e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -708,9 +708,10 @@
mView.setKeyguardMediaControllorVisible(visible);
if (visible) {
mView.generateAddAnimation(
- mKeyguardMediaController.getView(), false /*fromMoreCard */);
+ mKeyguardMediaController.getSinglePaneContainer(),
+ false /*fromMoreCard */);
} else {
- mView.generateRemoveAnimation(mKeyguardMediaController.getView());
+ mView.generateRemoveAnimation(mKeyguardMediaController.getSinglePaneContainer());
}
mView.requestChildrenUpdate();
return Unit.INSTANCE;
@@ -780,7 +781,7 @@
return mView.isLayoutRtl();
}
- public float getLeft() {
+ public int getLeft() {
return mView.getLeft();
}
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 6cacec7..27ee13a 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
@@ -33,9 +33,7 @@
import com.android.systemui.statusbar.notification.row.FooterView;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
/**
* The Algorithm of the {@link com.android.systemui.statusbar.notification.stack
@@ -153,9 +151,7 @@
private void updateClipping(StackScrollAlgorithmState algorithmState,
AmbientState ambientState) {
- float drawStart = !ambientState.isOnKeyguard() ? ambientState.getTopPadding()
- + ambientState.getStackTranslation()
- : 0;
+ float drawStart = !ambientState.isOnKeyguard() ? ambientState.getStackY() : 0;
float clipStart = 0;
int childCount = algorithmState.visibleChildren.size();
boolean firstHeadsUp = true;
@@ -168,8 +164,7 @@
float newYTranslation = state.yTranslation;
float newHeight = state.height;
float newNotificationEnd = newYTranslation + newHeight;
- boolean isHeadsUp = (child instanceof ExpandableNotificationRow)
- && ((ExpandableNotificationRow) child).isPinned();
+ boolean isHeadsUp = (child instanceof ExpandableNotificationRow) && child.isPinned();
if (mClipNotificationScrollToTop
&& (!state.inShelf || (isHeadsUp && !firstHeadsUp))
&& newYTranslation < clipStart
@@ -255,16 +250,16 @@
}
}
- state.firstViewInShelf = null;
- // Save y, sectionStart, sectionEnd from when shade is fully expanded.
- // Consider updating these states in updateContentView instead so that we don't have to
- // recalculate in every frame.
+ // Save (height of view before shelf, index of first view in shelf) from when shade is fully
+ // expanded. Consider updating these states in updateContentView instead so that we don't
+ // have to recalculate in every frame.
float currentY = -scrollY;
- int sectionStartIndex = 0;
- int sectionEndIndex = 0;
+ float previousY = 0;
+ state.firstViewInShelf = null;
+ state.viewHeightBeforeShelf = -1;
for (int i = 0; i < state.visibleChildren.size(); i++) {
final ExpandableView view = state.visibleChildren.get(i);
- // Add space between sections.
+
final boolean applyGapHeight = childNeedsGapHeight(
ambientState.getSectionProvider(), i,
view, getPreviousView(i, state));
@@ -273,88 +268,27 @@
}
if (ambientState.getShelf() != null) {
- // Save index of first view in the shelf
final float shelfStart = ambientState.getStackEndHeight()
- ambientState.getShelf().getIntrinsicHeight();
if (currentY >= shelfStart
&& !(view instanceof FooterView)
&& state.firstViewInShelf == null) {
state.firstViewInShelf = view;
+ // There might be a section gap right before the shelf.
+ // Limit the height of the view before the shelf so that it does not include
+ // a gap and become taller than it normally is.
+ state.viewHeightBeforeShelf = Math.min(getMaxAllowedChildHeight(view),
+ ambientState.getStackEndHeight()
+ - ambientState.getShelf().getIntrinsicHeight()
+ - mPaddingBetweenElements
+ - previousY);
}
}
-
- // Record y position when fully expanded
- ExpansionData expansionData = new ExpansionData();
- expansionData.fullyExpandedY = currentY;
- state.expansionData.put(view, expansionData);
-
- if (ambientState.getSectionProvider()
- .beginsSection(view, getPreviousView(i, state))) {
-
- // Save section start/end for views in the section before this new section
- ExpandableView sectionStartView = state.visibleChildren.get(sectionStartIndex);
- final float sectionStart =
- state.expansionData.get(sectionStartView).fullyExpandedY;
-
- ExpandableView sectionEndView = state.visibleChildren.get(sectionEndIndex);
- float sectionEnd = state.expansionData.get(sectionEndView).fullyExpandedY
- + sectionEndView.getIntrinsicHeight();
-
- if (ambientState.getShelf() != null) {
- // If we show the shelf, trim section end to shelf start
- // This means section end > start for views in the shelf
- final float shelfStart = ambientState.getStackEndHeight()
- - ambientState.getShelf().getIntrinsicHeight();
- if (state.firstViewInShelf != null && sectionEnd > shelfStart) {
- sectionEnd = shelfStart;
- }
- }
-
- // Update section bounds of every view in the previous section
- // Consider using shared SectionInfo for views in same section to avoid looping back
- for (int j = sectionStartIndex; j < i; j++) {
- ExpandableView sectionView = state.visibleChildren.get(j);
- ExpansionData viewExpansionData =
- state.expansionData.get(sectionView);
- viewExpansionData.sectionStart = sectionStart;
- viewExpansionData.sectionEnd = sectionEnd;
- state.expansionData.put(sectionView, viewExpansionData);
- }
- sectionStartIndex = i;
-
- if (view instanceof FooterView) {
- // Also record section bounds for FooterView (same as its own)
- // because it is the last view and we won't get to this point again
- // after the loop ends
- ExpansionData footerExpansionData = state.expansionData.get(view);
- footerExpansionData.sectionStart = expansionData.fullyExpandedY;
- footerExpansionData.sectionEnd = expansionData.fullyExpandedY
- + view.getIntrinsicHeight();
- state.expansionData.put(view, footerExpansionData);
- }
- }
- sectionEndIndex = i;
+ previousY = currentY;
currentY = currentY
+ getMaxAllowedChildHeight(view)
+ mPaddingBetweenElements;
}
-
- // Which view starts the section of the view right before the shelf?
- // Save it for later when we clip views in that section to shelf start.
- state.firstViewInOverflowSection = null;
- if (state.firstViewInShelf != null) {
- ExpandableView nextView = null;
- final int startIndex = state.visibleChildren.indexOf(state.firstViewInShelf);
- for (int i = startIndex - 1; i >= 0; i--) {
- ExpandableView view = state.visibleChildren.get(i);
- if (nextView != null && ambientState.getSectionProvider()
- .beginsSection(nextView, view)) {
- break;
- }
- nextView = view;
- }
- state.firstViewInOverflowSection = nextView;
- }
}
private int updateNotGoneIndex(StackScrollAlgorithmState state, int notGoneIndex,
@@ -394,6 +328,26 @@
}
}
+ /**
+ * @return Fraction to apply to view height and gap between views.
+ * Does not include shelf height even if shelf is showing.
+ */
+ private float getExpansionFractionWithoutShelf(
+ StackScrollAlgorithmState algorithmState,
+ AmbientState ambientState) {
+
+ final boolean isShowingShelf = ambientState.getShelf() != null
+ && algorithmState.firstViewInShelf != null;
+
+ final float stackHeight = ambientState.getStackHeight()
+ - (isShowingShelf ? ambientState.getShelf().getIntrinsicHeight() : 0f);
+
+ float stackEndHeight = ambientState.getStackEndHeight()
+ - (isShowingShelf ? ambientState.getShelf().getIntrinsicHeight() : 0f);
+
+ return stackHeight / stackEndHeight;
+ }
+
// TODO(b/172289889) polish shade open from HUN
/**
* Populates the {@link ExpandableViewState} for a single child.
@@ -426,22 +380,8 @@
viewState.headsUpIsVisible = end < ambientState.getMaxHeadsUpTranslation();
}
- // TODO(b/172289889) move sectionFraction and showSection to initAlgorithmState
- // Get fraction of section showing, and later apply it to view height and gaps between views
- float sectionFraction = 1f;
- boolean showSection = true;
-
- if (!ambientState.isOnKeyguard()
- && !ambientState.isPulseExpanding()
- && ambientState.isExpansionChanging()) {
-
- final ExpansionData expansionData = algorithmState.expansionData.get(view);
- final float sectionHeight = expansionData.sectionEnd - expansionData.sectionStart;
- sectionFraction = MathUtils.constrain(
- (ambientState.getStackHeight() - expansionData.sectionStart) / sectionHeight,
- 0f, 1f);
- showSection = expansionData.sectionStart < ambientState.getStackHeight();
- }
+ final float expansionFraction = getExpansionFractionWithoutShelf(
+ algorithmState, ambientState);
// Add gap between sections.
final boolean applyGapHeight =
@@ -449,46 +389,58 @@
ambientState.getSectionProvider(), i,
view, getPreviousView(i, algorithmState));
if (applyGapHeight) {
- currentYPosition += sectionFraction * mGapHeight;
+ currentYPosition += expansionFraction * mGapHeight;
}
viewState.yTranslation = currentYPosition;
-
if (view instanceof SectionHeaderView) {
// Add padding before sections for overscroll effect.
- viewState.yTranslation += ambientState.getSectionPadding();
+ viewState.yTranslation += expansionFraction * ambientState.getSectionPadding();
}
- if (view != ambientState.getTrackedHeadsUpRow()) {
+ if (view instanceof FooterView) {
+ viewState.yTranslation = Math.min(viewState.yTranslation,
+ ambientState.getStackHeight());
+ // Hide footer if shelf is showing
+ viewState.hidden = algorithmState.firstViewInShelf != null;
+ } else if (view != ambientState.getTrackedHeadsUpRow()) {
if (ambientState.isExpansionChanging()) {
- viewState.hidden = !showSection;
+ // Show all views. Views below the shelf will later be clipped (essentially hidden)
+ // in NotificationShelf.
+ viewState.hidden = false;
viewState.inShelf = algorithmState.firstViewInShelf != null
&& i >= algorithmState.visibleChildren.indexOf(
- algorithmState.firstViewInShelf)
- && !(view instanceof FooterView);
+ algorithmState.firstViewInShelf);
} else if (ambientState.getShelf() != null) {
// When pulsing (incoming notification on AOD), innerHeight is 0; clamp all
// to shelf start, thereby hiding all notifications (except the first one, which we
// later unhide in updatePulsingState)
final int shelfStart = ambientState.getInnerHeight()
- ambientState.getShelf().getIntrinsicHeight();
- if (!(view instanceof FooterView)) {
- viewState.yTranslation = Math.min(viewState.yTranslation, shelfStart);
- }
+ viewState.yTranslation = Math.min(viewState.yTranslation, shelfStart);
if (viewState.yTranslation >= shelfStart) {
viewState.hidden = !view.isExpandAnimationRunning()
- && !view.hasExpandingChild()
- && !(view instanceof FooterView);
+ && !view.hasExpandingChild();
viewState.inShelf = true;
// Notifications in the shelf cannot be visible HUNs.
viewState.headsUpIsVisible = false;
}
}
- viewState.height = (int) MathUtils.lerp(
- 0, getMaxAllowedChildHeight(view), sectionFraction);
+
+ // Clip height of view right before shelf.
+ float maxViewHeight = getMaxAllowedChildHeight(view);
+ if (ambientState.isExpansionChanging()
+ && algorithmState.viewHeightBeforeShelf != -1) {
+ final int indexOfFirstViewInShelf = algorithmState.visibleChildren.indexOf(
+ algorithmState.firstViewInShelf);
+ if (i == indexOfFirstViewInShelf - 1) {
+ maxViewHeight = algorithmState.viewHeightBeforeShelf;
+ }
+ }
+ viewState.height = (int) MathUtils.lerp(0, maxViewHeight, expansionFraction);
}
- currentYPosition += viewState.height + sectionFraction * mPaddingBetweenElements;
+ currentYPosition += viewState.height + expansionFraction * mPaddingBetweenElements;
setLocation(view.getViewState(), currentYPosition, i);
viewState.yTranslation += ambientState.getStackY();
return currentYPosition;
@@ -743,35 +695,6 @@
this.mIsExpanded = isExpanded;
}
- /**
- * Data used to layout views while shade expansion changes.
- */
- public class ExpansionData {
-
- /**
- * Y position of top of first view in section.
- */
- public float sectionStart;
-
- /**
- * Y position of bottom of last view in section.
- */
- public float sectionEnd;
-
- /**
- * Y position of view when shade is fully expanded.
- * Does not include distance between top notifications panel and top of screen.
- */
- public float fullyExpandedY;
-
- /**
- * Whether this notification is in the same section as the notification right before the
- * shelf. Used to determine which notification should be clipped to shelf start while
- * shade expansion changes.
- */
- public boolean inOverflowingSection;
- }
-
public class StackScrollAlgorithmState {
/**
@@ -785,16 +708,9 @@
public ExpandableView firstViewInShelf;
/**
- * First view in section overflowing into shelf while shade expansion changes.
+ * Height of view right before the shelf.
*/
- public ExpandableView firstViewInOverflowSection;
-
- /**
- * Map of view to ExpansionData used for layout during shade expansion.
- * Use view instead of index as key, because visibleChildren indices do not match the ones
- * used in the shelf.
- */
- public Map<ExpandableView, ExpansionData> expansionData = new HashMap<>();
+ public float viewHeightBeforeShelf;
/**
* The children from the host view which are not gone.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index a4ee9ee..5399094 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -411,13 +411,22 @@
Trace.endSection();
break;
case MODE_UNLOCK_COLLAPSING:
- case MODE_SHOW_BOUNCER:
- Trace.beginSection("MODE_UNLOCK_COLLAPSING or MODE_SHOW_BOUNCER");
+ Trace.beginSection("MODE_UNLOCK_COLLAPSING");
if (!wasDeviceInteractive) {
mPendingShowBouncer = true;
} else {
showBouncer();
- mKeyguardViewController.notifyKeyguardAuthenticated(false /* strongAuth */);
+ mKeyguardViewController.notifyKeyguardAuthenticated(
+ false /* strongAuth */);
+ }
+ Trace.endSection();
+ break;
+ case MODE_SHOW_BOUNCER:
+ Trace.beginSection("MODE_SHOW_BOUNCER");
+ if (!wasDeviceInteractive) {
+ mPendingShowBouncer = true;
+ } else {
+ showBouncer();
}
Trace.endSection();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 48c7b89..76657ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -17,6 +17,7 @@
import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
import static android.app.StatusBarManager.DISABLE_CLOCK;
import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS;
+import static android.app.StatusBarManager.DISABLE_ONGOING_CALL_CHIP;
import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
@@ -92,6 +93,7 @@
private OngoingCallController mOngoingCallController;
private final SystemStatusAnimationScheduler mAnimationScheduler;
private final PrivacyDotViewController mDotViewController;
+ private NotificationIconAreaController mNotificationIconAreaController;
private List<String> mBlockedIcons = new ArrayList<>();
@@ -106,13 +108,11 @@
@Override
public void onOngoingCallStarted(boolean animate) {
disable(getContext().getDisplayId(), mDisabled1, mDisabled2, animate);
- animateShow(mOngoingCallChip, animate);
}
@Override
public void onOngoingCallEnded(boolean animate) {
disable(getContext().getDisplayId(), mDisabled1, mDisabled2, animate);
- animateHiddenState(mOngoingCallChip, View.GONE, animate);
}
};
@@ -120,11 +120,13 @@
public CollapsedStatusBarFragment(
OngoingCallController ongoingCallController,
SystemStatusAnimationScheduler animationScheduler,
- PrivacyDotViewController dotViewController
+ PrivacyDotViewController dotViewController,
+ NotificationIconAreaController notificationIconAreaController
) {
mOngoingCallController = ongoingCallController;
mAnimationScheduler = animationScheduler;
mDotViewController = dotViewController;
+ mNotificationIconAreaController = notificationIconAreaController;
}
@Override
@@ -168,6 +170,7 @@
showClock(false);
initEmergencyCryptkeeperText();
initOperatorName();
+ initNotificationIconArea();
mAnimationScheduler.addCallback(this);
}
@@ -204,11 +207,11 @@
}
}
- public void initNotificationIconArea(NotificationIconAreaController
- notificationIconAreaController) {
+ /** Initializes views related to the notification icon area. */
+ public void initNotificationIconArea() {
ViewGroup notificationIconArea = mStatusBar.findViewById(R.id.notification_icon_area);
mNotificationIconAreaInner =
- notificationIconAreaController.getNotificationInnerAreaView();
+ mNotificationIconAreaController.getNotificationInnerAreaView();
if (mNotificationIconAreaInner.getParent() != null) {
((ViewGroup) mNotificationIconAreaInner.getParent())
.removeView(mNotificationIconAreaInner);
@@ -216,15 +219,15 @@
notificationIconArea.addView(mNotificationIconAreaInner);
ViewGroup statusBarCenteredIconArea = mStatusBar.findViewById(R.id.centered_icon_area);
- mCenteredIconArea = notificationIconAreaController.getCenteredNotificationAreaView();
+ mCenteredIconArea = mNotificationIconAreaController.getCenteredNotificationAreaView();
if (mCenteredIconArea.getParent() != null) {
((ViewGroup) mCenteredIconArea.getParent())
.removeView(mCenteredIconArea);
}
statusBarCenteredIconArea.addView(mCenteredIconArea);
- // Default to showing until we know otherwise.
- showNotificationIconArea(false);
+ // #disable should have already been called, so use the disable values to set visibility.
+ updateNotificationIconAreaAndCallChip(mDisabled1, false);
}
@Override
@@ -249,13 +252,14 @@
showOperatorName(animate);
}
}
- if ((diff1 & DISABLE_NOTIFICATION_ICONS) != 0) {
- if ((state1 & DISABLE_NOTIFICATION_ICONS) != 0) {
- hideNotificationIconArea(animate);
- } else {
- showNotificationIconArea(animate);
- }
+
+ // The ongoing call chip and notification icon visibilities are intertwined, so update both
+ // if either change.
+ if (((diff1 & DISABLE_ONGOING_CALL_CHIP) != 0)
+ || ((diff1 & DISABLE_NOTIFICATION_ICONS) != 0)) {
+ updateNotificationIconAreaAndCallChip(state1, animate);
}
+
// The clock may have already been hidden, but we might want to shift its
// visibility to GONE from INVISIBLE or vice versa
if ((diff1 & DISABLE_CLOCK) != 0 || mClockView.getVisibility() != clockHiddenMode()) {
@@ -273,10 +277,6 @@
state |= DISABLE_CLOCK;
}
- if (mOngoingCallController.hasOngoingCall()) {
- state |= DISABLE_NOTIFICATION_ICONS;
- }
-
if (!mKeyguardStateController.isLaunchTransitionFadingAway()
&& !mKeyguardStateController.isKeyguardFadingAway()
&& shouldHideNotificationIcons()
@@ -304,9 +304,40 @@
state |= DISABLE_CLOCK | DISABLE_SYSTEM_INFO;
}
+ if (mOngoingCallController.hasOngoingCall()) {
+ state &= ~DISABLE_ONGOING_CALL_CHIP;
+ } else {
+ state |= DISABLE_ONGOING_CALL_CHIP;
+ }
+
return state;
}
+ /**
+ * Updates the visibility of the notification icon area and ongoing call chip based on disabled1
+ * state.
+ */
+ private void updateNotificationIconAreaAndCallChip(int state1, boolean animate) {
+ boolean disableNotifications = (state1 & DISABLE_NOTIFICATION_ICONS) != 0;
+ boolean hasOngoingCall = (state1 & DISABLE_ONGOING_CALL_CHIP) == 0;
+
+ // Hide notifications if the disable flag is set or we have an ongoing call.
+ if (disableNotifications || hasOngoingCall) {
+ hideNotificationIconArea(animate);
+ } else {
+ showNotificationIconArea(animate);
+ }
+
+ // Show the ongoing call chip only if there is an ongoing call *and* notification icons
+ // are allowed. (The ongoing call chip occupies the same area as the notification icons,
+ // so if the icons are disabled then the call chip should be, too.)
+ if (hasOngoingCall && !disableNotifications) {
+ showOngoingCallChip(animate);
+ } else {
+ hideOngoingCallChip(animate);
+ }
+ }
+
private boolean shouldHideNotificationIcons() {
if (!mStatusBar.isClosed() && mStatusBarComponent.hideStatusBarIconsWhenExpanded()) {
return true;
@@ -336,6 +367,16 @@
animateShow(mClockView, animate);
}
+ /** Hides the ongoing call chip. */
+ public void hideOngoingCallChip(boolean animate) {
+ animateHiddenState(mOngoingCallChip, View.GONE, animate);
+ }
+
+ /** Displays the ongoing call chip. */
+ public void showOngoingCallChip(boolean animate) {
+ animateShow(mOngoingCallChip, animate);
+ }
+
/**
* If panel is expanded/expanding it usually means QS shade is opening, so
* don't set the clock GONE otherwise it'll mess up the animation.
@@ -457,7 +498,7 @@
@Override
public void onDozingChanged(boolean isDozing) {
- disable(getContext().getDisplayId(), mDisabled1, mDisabled1, false /* animate */);
+ disable(getContext().getDisplayId(), mDisabled1, mDisabled2, false /* animate */);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 8cef23f..cabfbca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -935,7 +935,9 @@
private void onWalletClick(View v) {
// More coming here; need to inform the user about how to proceed
- mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY);
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ return;
+ }
if (mHasCard) {
Intent intent = new Intent(mContext, WalletActivity.class)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 481b2db..069c197 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -155,6 +155,8 @@
private int mLockScreenMode;
+ private boolean mIsSplitShade;
+
/**
* Refreshes the dimension values.
*/
@@ -180,7 +182,7 @@
int keyguardStatusHeight, int userSwitchHeight, int clockPreferredY,
int userSwitchPreferredY, boolean hasCustomClock, boolean hasVisibleNotifs, float dark,
float emptyDragAmount, boolean bypassEnabled, int unlockedStackScrollerPadding,
- float qsExpansion, int cutoutTopInset) {
+ float qsExpansion, int cutoutTopInset, boolean isSplitShade) {
mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding,
userSwitchHeight);
mMaxShadeBottom = maxShadeBottom;
@@ -199,6 +201,7 @@
mUnlockedStackScrollerPadding = unlockedStackScrollerPadding;
mQsExpansion = qsExpansion;
mCutoutTopInset = cutoutTopInset;
+ mIsSplitShade = isSplitShade;
}
public void run(Result result) {
@@ -208,14 +211,23 @@
result.clockYFullyDozing = getClockY(
1.0f /* panelExpansion */, 1.0f /* darkAmount */);
result.clockAlpha = getClockAlpha(y);
- result.stackScrollerPadding = mBypassEnabled ? mUnlockedStackScrollerPadding
- : y + mKeyguardStatusHeight;
+ result.stackScrollerPadding = getStackScrollerPadding(y);
result.stackScrollerPaddingExpanded = mBypassEnabled ? mUnlockedStackScrollerPadding
: getClockY(1.0f, mDarkAmount) + mKeyguardStatusHeight;
result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
result.clockScale = interpolate(getBurnInScale(), 1.0f, 1.0f - mDarkAmount);
}
+ private int getStackScrollerPadding(int clockYPosition) {
+ if (mBypassEnabled) {
+ return mUnlockedStackScrollerPadding;
+ } else if (mIsSplitShade) {
+ return clockYPosition;
+ } else {
+ return clockYPosition + mKeyguardStatusHeight;
+ }
+ }
+
/**
* Update lock screen mode for testing different layouts
*/
@@ -232,15 +244,11 @@
return mHeight / 2 - mKeyguardStatusHeight - mClockNotificationsMargin;
}
- private int getPreferredClockY() {
- return mClockPreferredY;
- }
-
private int getExpandedPreferredClockY() {
if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
return mMinTopMargin + mUserSwitchHeight;
}
- return (mHasCustomClock && (!mHasVisibleNotifs || mBypassEnabled)) ? getPreferredClockY()
+ return (mHasCustomClock && (!mHasVisibleNotifs || mBypassEnabled)) ? mClockPreferredY
: getExpandedClockPosition();
}
@@ -271,7 +279,7 @@
private int getClockY(float panelExpansion, float darkAmount) {
// Dark: Align the bottom edge of the clock at about half of the screen:
- float clockYDark = (mHasCustomClock ? getPreferredClockY() : getMaxClockY())
+ float clockYDark = (mHasCustomClock ? mClockPreferredY : getMaxClockY())
+ burnInPreventionOffsetY();
clockYDark = MathUtils.max(0, clockYDark);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 16f36b7..5168533 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -16,127 +16,25 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.DejankUtils.whitelistIpcs;
-
import android.content.Context;
-import android.os.UserManager;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Button;
import android.widget.FrameLayout;
-import com.android.systemui.Dependency;
-import com.android.systemui.Prefs;
-import com.android.systemui.Prefs.Key;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.DetailAdapter;
-import com.android.systemui.qs.QSDetailDisplayer;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
/**
* Container for image of the multi user switcher (tappable).
*/
-public class MultiUserSwitch extends FrameLayout implements View.OnClickListener {
-
- protected QSDetailDisplayer mQSDetailDisplayer;
- private UserSwitcherController.BaseUserAdapter mUserListener;
-
- final UserManager mUserManager;
-
-
- protected UserSwitcherController mUserSwitcherController;
-
+public class MultiUserSwitch extends FrameLayout {
public MultiUserSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
- mUserManager = UserManager.get(getContext());
}
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- setOnClickListener(this);
- refreshContentDescription();
- }
-
- /** */
- public void setQSDetailDisplayer(QSDetailDisplayer detailDisplayer) {
- mQSDetailDisplayer = detailDisplayer;
- setUserSwitcherController(Dependency.get(UserSwitcherController.class));
- }
-
- public boolean hasMultipleUsers() {
- if (mUserListener == null) {
- return false;
- }
- return mUserListener.getUserCount() != 0
- && Prefs.getBoolean(getContext(), Key.SEEN_MULTI_USER, false);
- }
-
- public void setUserSwitcherController(UserSwitcherController userSwitcherController) {
- mUserSwitcherController = userSwitcherController;
- registerListener();
- refreshContentDescription();
- }
-
- public boolean isMultiUserEnabled() {
- // TODO(b/138661450) Move IPC calls to background
- return whitelistIpcs(() -> mUserManager.isUserSwitcherEnabled(
- mContext.getResources().getBoolean(R.bool.qs_show_user_switcher_for_single_user)));
- }
-
- private void registerListener() {
- if (mUserManager.isUserSwitcherEnabled() && mUserListener == null) {
-
- final UserSwitcherController controller = mUserSwitcherController;
- if (controller != null) {
- mUserListener = new UserSwitcherController.BaseUserAdapter(controller) {
- @Override
- public void notifyDataSetChanged() {
- refreshContentDescription();
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- return null;
- }
- };
- refreshContentDescription();
- }
- }
- }
-
- @Override
- public void onClick(View v) {
- if (mQSDetailDisplayer != null && mUserSwitcherController != null) {
- View center = getChildCount() > 0 ? getChildAt(0) : this;
-
- int[] tmpInt = new int[2];
- center.getLocationInWindow(tmpInt);
- tmpInt[0] += center.getWidth() / 2;
- tmpInt[1] += center.getHeight() / 2;
-
- mQSDetailDisplayer.showDetailAdapter(getUserDetailAdapter(), tmpInt[0], tmpInt[1]);
- }
- }
-
- @Override
- public void setClickable(boolean clickable) {
- super.setClickable(clickable);
- refreshContentDescription();
- }
-
- private void refreshContentDescription() {
- String currentUser = null;
- // TODO(b/138661450)
- if (whitelistIpcs(() -> mUserManager.isUserSwitcherEnabled())
- && mUserSwitcherController != null) {
- currentUser = mUserSwitcherController.getCurrentUserName(mContext);
- }
-
+ void refreshContentDescription(String currentUser) {
String text = null;
if (!TextUtils.isEmpty(currentUser)) {
@@ -166,8 +64,4 @@
public boolean hasOverlappingRendering() {
return false;
}
-
- protected DetailAdapter getUserDetailAdapter() {
- return mUserSwitcherController.mUserDetailAdapter;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
new file mode 100644
index 0000000..f27c7d2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
+import android.os.UserManager;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.qs.DetailAdapter;
+import com.android.systemui.qs.QSDetailDisplayer;
+import com.android.systemui.qs.dagger.QSScope;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+
+/** View Controller for {@link MultiUserSwitch}. */
+@QSScope
+public class MultiUserSwitchController extends ViewController<MultiUserSwitch> {
+ private final UserManager mUserManager;
+ private final UserSwitcherController mUserSwitcherController;
+ private final QSDetailDisplayer mQsDetailDisplayer;
+ private final FalsingManager mFalsingManager;
+
+ private UserSwitcherController.BaseUserAdapter mUserListener;
+
+ private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ return;
+ }
+
+ View center = mView.getChildCount() > 0 ? mView.getChildAt(0) : mView;
+
+ int[] tmpInt = new int[2];
+ center.getLocationInWindow(tmpInt);
+ tmpInt[0] += center.getWidth() / 2;
+ tmpInt[1] += center.getHeight() / 2;
+
+ mQsDetailDisplayer.showDetailAdapter(getUserDetailAdapter(), tmpInt[0], tmpInt[1]);
+ }
+ };
+
+ @Inject
+ public MultiUserSwitchController(MultiUserSwitch view, UserManager userManager,
+ UserSwitcherController userSwitcherController, QSDetailDisplayer qsDetailDisplayer,
+ FalsingManager falsingManager) {
+ super(view);
+ mUserManager = userManager;
+ mUserSwitcherController = userSwitcherController;
+ mQsDetailDisplayer = qsDetailDisplayer;
+ mFalsingManager = falsingManager;
+ }
+
+ @Override
+ protected void onInit() {
+ registerListener();
+ mView.refreshContentDescription(getCurrentUser());
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mView.setOnClickListener(mOnClickListener);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mView.setOnClickListener(null);
+ }
+
+ protected DetailAdapter getUserDetailAdapter() {
+ return mUserSwitcherController.mUserDetailAdapter;
+ }
+
+ private void registerListener() {
+ if (mUserManager.isUserSwitcherEnabled() && mUserListener == null) {
+
+ final UserSwitcherController controller = mUserSwitcherController;
+ if (controller != null) {
+ mUserListener = new UserSwitcherController.BaseUserAdapter(controller) {
+ @Override
+ public void notifyDataSetChanged() {
+ mView.refreshContentDescription(getCurrentUser());
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ return null;
+ }
+ };
+ mView.refreshContentDescription(getCurrentUser());
+ }
+ }
+ }
+
+ private String getCurrentUser() {
+ // TODO(b/138661450)
+ if (whitelistIpcs(() -> mUserManager.isUserSwitcherEnabled())) {
+ return mUserSwitcherController.getCurrentUserName();
+ }
+
+ return null;
+ }
+
+ /** Returns true if view should be made visible. */
+ public boolean isMultiUserEnabled() {
+ // TODO(b/138661450) Move IPC calls to background
+ return whitelistIpcs(() -> mUserManager.isUserSwitcherEnabled(
+ getResources().getBoolean(R.bool.qs_show_user_switcher_for_single_user)));
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 961699e..8574830e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -28,6 +28,7 @@
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
+import static com.android.systemui.util.Utils.shouldUseSplitNotificationShade;
import static java.lang.Float.isNaN;
@@ -53,6 +54,7 @@
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UserManager;
+import android.os.VibrationEffect;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.util.Log;
import android.util.MathUtils;
@@ -98,9 +100,11 @@
import com.android.systemui.doze.DozeLog;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
+import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.FalsingManager.FalsingTapListener;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -206,6 +210,7 @@
private final ExpansionCallback mExpansionCallback = new ExpansionCallback();
private final BiometricUnlockController mBiometricUnlockController;
private final NotificationPanelView mView;
+ private final VibratorHelper mVibratorHelper;
private final MetricsLogger mMetricsLogger;
private final ActivityManager mActivityManager;
private final ConfigurationController mConfigurationController;
@@ -515,6 +520,7 @@
private boolean mDelayShowingKeyguardStatusBar;
private boolean mAnimatingQS;
+ private final Rect mKeyguardStatusAreaClipBounds = new Rect();
private int mOldLayoutDirection;
private NotificationShelfController mNotificationShelfController;
@@ -522,6 +528,8 @@
private final Executor mUiExecutor;
private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
+ private int mScrimCornerRadius;
+ private KeyguardMediaController mKeyguardMediaController;
private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
@Override
@@ -543,6 +551,14 @@
}
};
+ private final FalsingTapListener mFalsingTapListener = new FalsingTapListener() {
+ @Override
+ public void onDoubleTapRequired() {
+ showTransientIndication(R.string.notification_tap_again);
+ mVibratorHelper.vibrate(VibrationEffect.EFFECT_STRENGTH_MEDIUM);
+ }
+ };
+
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@Main Resources resources,
@@ -584,12 +600,15 @@
LockIconViewController lockIconViewController,
FeatureFlags featureFlags,
QuickAccessWalletClient quickAccessWalletClient,
+ KeyguardMediaController keyguardMediaController,
@Main Executor uiExecutor) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
statusBarKeyguardViewManager, latencyTracker, flingAnimationUtilsBuilder.get(),
statusBarTouchableRegionManager, ambientState);
mView = view;
+ mVibratorHelper = vibratorHelper;
+ mKeyguardMediaController = keyguardMediaController;
mMetricsLogger = metricsLogger;
mActivityManager = activityManager;
mConfigurationController = configurationController;
@@ -628,6 +647,7 @@
mDozeParameters = dozeParameters;
mBiometricUnlockController = biometricUnlockController;
mScrimController = scrimController;
+ mScrimController.setClipsQsScrim(!mShouldUseSplitNotificationShade);
mUserManager = userManager;
mMediaDataManager = mediaDataManager;
mQuickAccessWalletClient = quickAccessWalletClient;
@@ -756,7 +776,6 @@
});
mView.setAccessibilityDelegate(mAccessibilityDelegate);
- // dynamically apply the split shade value overrides.
if (mShouldUseSplitNotificationShade) {
updateResources();
}
@@ -852,10 +871,16 @@
public void updateResources() {
mSplitShadeNotificationsTopPadding =
mResources.getDimensionPixelSize(R.dimen.notifications_top_padding_split_shade);
+ mScrimCornerRadius =
+ mResources.getDimensionPixelSize(R.dimen.notification_scrim_corner_radius);
int qsWidth = mResources.getDimensionPixelSize(R.dimen.qs_panel_width);
int panelWidth = mResources.getDimensionPixelSize(R.dimen.notification_panel_width);
mShouldUseSplitNotificationShade =
Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources);
+ mScrimController.setClipsQsScrim(!mShouldUseSplitNotificationShade);
+ if (mQs != null) {
+ mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade);
+ }
// To change the constraints at runtime, all children of the ConstraintLayout must have ids
ensureAllViewsHaveIds(mNotificationContainerParent);
ConstraintSet constraintSet = new ConstraintSet();
@@ -868,13 +893,17 @@
constraintSet.connect(
R.id.notification_stack_scroller, START,
R.id.qs_edge_guideline, START);
+ constraintSet.connect(R.id.keyguard_status_view, END, R.id.qs_edge_guideline, END);
} else {
constraintSet.connect(R.id.qs_frame, END, PARENT_ID, END);
constraintSet.connect(R.id.notification_stack_scroller, START, PARENT_ID, START);
+ constraintSet.connect(R.id.keyguard_status_view, END, PARENT_ID, END);
}
constraintSet.getConstraint(R.id.notification_stack_scroller).layout.mWidth = panelWidth;
constraintSet.getConstraint(R.id.qs_frame).layout.mWidth = qsWidth;
constraintSet.applyTo(mNotificationContainerParent);
+
+ mKeyguardMediaController.refreshMediaPosition();
}
private static void ensureAllViewsHaveIds(ViewGroup parentView) {
@@ -908,12 +937,18 @@
private void reInflateViews() {
if (DEBUG) Log.d(TAG, "reInflateViews");
// Re-inflate the status view group.
- KeyguardStatusView keyguardStatusView = mView.findViewById(R.id.keyguard_status_view);
- int index = mView.indexOfChild(keyguardStatusView);
- mView.removeView(keyguardStatusView);
+ KeyguardStatusView keyguardStatusView =
+ mNotificationContainerParent.findViewById(R.id.keyguard_status_view);
+ int statusIndex = mNotificationContainerParent.indexOfChild(keyguardStatusView);
+ mNotificationContainerParent.removeView(keyguardStatusView);
keyguardStatusView = (KeyguardStatusView) mLayoutInflater.inflate(
- R.layout.keyguard_status_view, mView, false);
- mView.addView(keyguardStatusView, index);
+ R.layout.keyguard_status_view, mNotificationContainerParent, false);
+ mNotificationContainerParent.addView(keyguardStatusView, statusIndex);
+ attachSplitShadeMediaPlayerContainer(
+ keyguardStatusView.findViewById(R.id.status_view_media_container));
+
+ // we need to update KeyguardStatusView constraints after reinflating it
+ updateResources();
// Re-inflate the keyguard user switcher group.
boolean isUserSwitcherEnabled = mUserManager.isUserSwitcherEnabled();
@@ -935,11 +970,11 @@
showKeyguardUserSwitcher /* enabled */);
mBigClockContainer.removeAllViews();
- updateViewControllers(
- keyguardStatusView, userAvatarView, mKeyguardStatusBar, keyguardUserSwitcherView);
+ updateViewControllers(mView.findViewById(R.id.keyguard_status_view), userAvatarView,
+ mKeyguardStatusBar, keyguardUserSwitcherView);
// Update keyguard bottom area
- index = mView.indexOfChild(mKeyguardBottomArea);
+ int index = mView.indexOfChild(mKeyguardBottomArea);
mView.removeView(mKeyguardBottomArea);
KeyguardBottomAreaView oldBottomArea = mKeyguardBottomArea;
mKeyguardBottomArea = (KeyguardBottomAreaView) mLayoutInflater.inflate(
@@ -977,6 +1012,11 @@
setKeyguardBottomAreaVisibility(mBarState, false);
}
+ private void attachSplitShadeMediaPlayerContainer(FrameLayout container) {
+ mKeyguardMediaController.attachSplitShadeContainer(container,
+ () -> mShouldUseSplitNotificationShade);
+ }
+
private void initBottomArea() {
mAffordanceHelper = new KeyguardAffordanceHelper(
mKeyguardAffordanceHelperCallback, mView.getContext(), mFalsingManager);
@@ -1089,7 +1129,8 @@
hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount,
bypassEnabled, getUnlockedStackScrollerPadding(),
getQsExpansionFraction(),
- mDisplayCutoutTopInset);
+ mDisplayCutoutTopInset,
+ shouldUseSplitNotificationShade(mFeatureFlags, mResources));
mClockPositionAlgorithm.run(mClockPositionResult);
mKeyguardStatusViewController.updatePosition(
mClockPositionResult.clockX, mClockPositionResult.clockY,
@@ -1374,6 +1415,7 @@
protected void flingToHeight(float vel, boolean expand, float target,
float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
mHeadsUpTouchHelper.notifyFling(!expand);
+ mKeyguardStateController.notifyPanelFlingStart(!expand /* flingingToDismiss */);
setClosingWithAlphaFadeout(!expand && !isOnKeyguard() && getFadeoutAlpha() == 1.0f);
super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
}
@@ -2003,15 +2045,23 @@
mDepthController.setQsPanelExpansion(qsExpansionFraction);
}
- private void setNotificationBounds(float qsExpansionFraction, int qsPanelBottomY) {
- float top = 0;
- float bottom = 0;
- float left = 0;
- float right = 0;
- if (qsPanelBottomY > 0) {
- // notification shade is expanding/expanded
+ /**
+ * Updates scrim bounds, QS clipping, and KSV clipping as well based on the bounds of the shade
+ * and QS state.
+ *
+ * @param qsFraction QS expansion fraction, from getQsExpansionFraction().
+ * @param qsPanelBottomY Absolute y position of the bottom of QS as it's being pulled.
+ */
+ private void setNotificationBounds(float qsFraction, int qsPanelBottomY) {
+ int top = 0;
+ int bottom = 0;
+ int left = 0;
+ int right = 0;
+ boolean visible = qsFraction > 0 || qsPanelBottomY > 0;
+ if (visible || !mShouldUseSplitNotificationShade) {
if (!mShouldUseSplitNotificationShade) {
- top = qsPanelBottomY;
+ float notificationTop = mAmbientState.getStackY() - mQsNotificationTopPadding;
+ top = (int) Math.min(qsPanelBottomY, notificationTop);
bottom = getView().getBottom();
left = getView().getLeft();
right = getView().getRight();
@@ -2022,6 +2072,17 @@
right = mNotificationStackScrollLayoutController.getRight();
}
}
+
+ if (!mShouldUseSplitNotificationShade) {
+ // Fancy clipping for quick settings
+ if (mQs != null) {
+ mQs.setFancyClipping(top, bottom, mScrimCornerRadius, visible);
+ }
+ // The padding on this area is large enough that we can use a cheaper clipping strategy
+ mKeyguardStatusAreaClipBounds.set(left, top, right, bottom);
+ mKeyguardStatusViewController.setClipBounds(visible
+ ? mKeyguardStatusAreaClipBounds : null);
+ }
mScrimController.setNotificationsBounds(left, top, right, bottom);
}
@@ -2493,6 +2554,10 @@
float appearAmount = mNotificationStackScrollLayoutController
.calculateAppearFraction(mExpandedHeight);
float startHeight = -mQsExpansionHeight;
+ if (!mShouldUseSplitNotificationShade && mBarState == StatusBarState.SHADE) {
+ // Small parallax as we pull down and clip QS
+ startHeight = -mQsExpansionHeight * 0.2f;
+ }
if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()
&& mNotificationStackScrollLayoutController.isPulseExpanding()) {
if (!mPulseExpansionHandler.isExpanding()
@@ -3128,8 +3193,10 @@
mQs.setPanelView(mHeightListener);
mQs.setExpandClickListener(mOnClickListener);
mQs.setHeaderClickable(mQsExpansionEnabled);
+ mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade);
updateQSPulseExpansion();
mQs.setOverscrolling(mStackScrollerOverscrolling);
+ mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade);
// recompute internal state when qspanel height changes
mQs.getView().addOnLayoutChangeListener(
@@ -3925,7 +3992,10 @@
// animate out
// the top of QS
if (!mQsExpanded) {
- mQs.animateHeaderSlidingOut();
+ // TODO(b/185683835) Nicer clipping when using new spacial model
+ if (mShouldUseSplitNotificationShade) {
+ mQs.animateHeaderSlidingOut();
+ }
}
} else {
mKeyguardStatusBar.setAlpha(1f);
@@ -3978,6 +4048,7 @@
// window, so
// force a call to onThemeChanged
mConfigurationListener.onThemeChanged();
+ mFalsingManager.addTapListener(mFalsingTapListener);
}
@Override
@@ -3986,6 +4057,7 @@
mStatusBarStateController.removeCallback(mStatusBarStateListener);
mConfigurationController.removeCallback(mConfigurationListener);
mUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
+ mFalsingManager.removeTapListener(mFalsingTapListener);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 0c8122c..388d72d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -256,7 +256,12 @@
state.mScrimsVisibility == ScrimController.OPAQUE;
final boolean keyguardOrAod = state.mKeyguardShowing
|| (state.mDozing && mDozeParameters.getAlwaysOn());
- if (keyguardOrAod && !state.mBackdropShowing && !scrimsOccludingWallpaper) {
+ if ((keyguardOrAod && !state.mBackdropShowing && !scrimsOccludingWallpaper)
+ || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) {
+ // Show the wallpaper if we're on keyguard/AOD and the wallpaper is not occluded by a
+ // solid backdrop or scrim. Also, show it if we are currently animating between the
+ // keyguard and the surface behind the keyguard - we want to use the wallpaper as a
+ // backdrop for this animation.
mLpChanged.flags |= LayoutParams.FLAG_SHOW_WALLPAPER;
} else {
mLpChanged.flags &= ~LayoutParams.FLAG_SHOW_WALLPAPER;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 064086a..4714c4b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -147,9 +147,6 @@
private float mInitialTouchX;
private boolean mTouchDisabled;
- // AmbientState will never be null since it provides an @Inject constructor for Dagger to call.
- private AmbientState mAmbientState;
-
/**
* Whether or not the PanelView can be expanded or collapsed with a drag.
*/
@@ -172,6 +169,7 @@
protected final Resources mResources;
protected final KeyguardStateController mKeyguardStateController;
protected final SysuiStatusBarStateController mStatusBarStateController;
+ protected final AmbientState mAmbientState;
protected void onExpandingFinished() {
mBar.onExpandingFinished();
@@ -594,6 +592,7 @@
float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
if (target == mExpandedHeight || getOverExpansionAmount() > 0f && expand) {
InteractionJankMonitor.getInstance().end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+ mKeyguardStateController.notifyPanelFlingEnd();
notifyExpandingFinished();
return;
}
@@ -681,6 +680,7 @@
private void onFlingEnd(boolean cancelled) {
setAnimator(null);
+ mKeyguardStateController.notifyPanelFlingEnd();
if (!cancelled) {
InteractionJankMonitor.getInstance()
.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 5e9c758..0d96ead 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -48,8 +48,8 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.scrim.ScrimView;
import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.stack.ViewState;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -96,6 +96,7 @@
* When at least 1 scrim is fully opaque (alpha set to 1.)
*/
public static final int OPAQUE = 2;
+ private boolean mClipsQsScrim;
@IntDef(prefix = {"VISIBILITY_"}, value = {
TRANSPARENT,
@@ -165,6 +166,7 @@
// Assuming the shade is expanded during initialization
private float mExpansionFraction = 1f;
private float mQsExpansion;
+ private boolean mQsBottomVisible;
private boolean mDarkenWhileDragging;
private boolean mExpansionAffectsAlpha = true;
@@ -183,6 +185,7 @@
private int mInFrontTint;
private int mBehindTint;
+ private int mNotificationsTint;
private int mBubbleTint;
private boolean mWallpaperVisibilityTimedOut;
@@ -265,6 +268,7 @@
mScrimForBubble = scrimForBubble;
updateThemeColors();
+ behindScrim.enableBottomEdgeConcave(mClipsQsScrim);
mNotificationsScrim.enableRoundedCorners();
if (mScrimBehindChangeRunnable != null) {
@@ -331,14 +335,17 @@
mInFrontTint = state.getFrontTint();
mBehindTint = state.getBehindTint();
+ mNotificationsTint = state.getNotifTint();
mBubbleTint = state.getBubbleTint();
mInFrontAlpha = state.getFrontAlpha();
mBehindAlpha = state.getBehindAlpha();
mBubbleAlpha = state.getBubbleAlpha();
- if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha)) {
+ mNotificationsAlpha = state.getNotifAlpha();
+ if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha) || isNaN(mNotificationsAlpha)) {
throw new IllegalStateException("Scrim opacity is NaN for state: " + state + ", front: "
- + mInFrontAlpha + ", back: " + mBehindAlpha);
+ + mInFrontAlpha + ", back: " + mBehindAlpha + ", notif: "
+ + mNotificationsAlpha);
}
applyExpansionToAlpha();
@@ -397,7 +404,7 @@
scheduleUpdate();
}
- dispatchScrimState(mScrimBehind.getViewAlpha());
+ dispatchBackScrimState(mScrimBehind.getViewAlpha());
}
private boolean shouldFadeAwayWallpaper() {
@@ -491,21 +498,25 @@
*/
public void setNotificationsBounds(float left, float top, float right, float bottom) {
mNotificationsScrim.setDrawableBounds(left, top, right, bottom);
+ if (mClipsQsScrim) {
+ mScrimBehind.setBottomEdgePosition((int) top);
+ }
}
/**
* Current state of the QuickSettings when pulling it from the top.
*
* @param expansionFraction From 0 to 1 where 0 means collapsed and 1 expanded.
- * @param qsPanelBottomY absolute Y position of qs panel bottom
+ * @param qsPanelBottomY Absolute Y position of qs panel bottom
*/
public void setQsPosition(float expansionFraction, int qsPanelBottomY) {
if (isNaN(expansionFraction)) {
return;
}
- updateNotificationsScrimAlpha(expansionFraction, qsPanelBottomY);
- if (mQsExpansion != expansionFraction) {
+ boolean qsBottomVisible = qsPanelBottomY > 0;
+ if (mQsExpansion != expansionFraction || mQsBottomVisible != qsBottomVisible) {
mQsExpansion = expansionFraction;
+ mQsBottomVisible = qsBottomVisible;
boolean relevantState = (mState == ScrimState.SHADE_LOCKED
|| mState == ScrimState.KEYGUARD
|| mState == ScrimState.PULSING
@@ -517,22 +528,26 @@
}
}
- private void updateNotificationsScrimAlpha(float qsExpansion, int qsPanelBottomY) {
- float newAlpha = 0;
- if (qsPanelBottomY > 0) {
- float interpolator = 0;
- if (mState == ScrimState.UNLOCKED || mState == ScrimState.SHADE_LOCKED) {
- interpolator = getInterpolatedFraction();
- } else {
- interpolator = qsExpansion;
- }
- newAlpha = MathUtils.lerp(0, 1, interpolator);
+ /**
+ * If QS and notification scrims should not overlap, and should be clipped to each other's
+ * bounds instead.
+ */
+ public void setClipsQsScrim(boolean clipScrim) {
+ if (clipScrim == mClipsQsScrim) {
+ return;
}
- if (newAlpha != mNotificationsAlpha) {
- mNotificationsAlpha = newAlpha;
- // update alpha without animating
- mNotificationsScrim.setViewAlpha(newAlpha);
+ mClipsQsScrim = clipScrim;
+ for (ScrimState state : ScrimState.values()) {
+ state.setClipQsScrim(mClipsQsScrim);
}
+ if (mScrimBehind != null) {
+ mScrimBehind.enableBottomEdgeConcave(mClipsQsScrim);
+ }
+ }
+
+ @VisibleForTesting
+ public boolean getClipQsScrim() {
+ return mClipsQsScrim;
}
private void setOrAdaptCurrentAnimation(@Nullable View scrim) {
@@ -541,7 +556,8 @@
}
float alpha = getCurrentScrimAlpha(scrim);
- if (isAnimating(scrim)) {
+ boolean qsScrimPullingDown = scrim == mScrimBehind && mQsBottomVisible;
+ if (isAnimating(scrim) && !qsScrimPullingDown) {
// Adapt current animation.
ValueAnimator previousAnimator = (ValueAnimator) scrim.getTag(TAG_KEY_ANIM);
float previousEndValue = (Float) scrim.getTag(TAG_END_ALPHA);
@@ -562,7 +578,19 @@
return;
}
- if (mState == ScrimState.UNLOCKED || mState == ScrimState.BUBBLE_EXPANDED) {
+ if (mState == ScrimState.UNLOCKED) {
+ // Darken scrim as you pull down the shade when unlocked
+ float behindFraction = getInterpolatedFraction();
+ behindFraction = (float) Math.pow(behindFraction, 0.8f);
+ if (mClipsQsScrim) {
+ mBehindAlpha = 1;
+ mNotificationsAlpha = behindFraction * mDefaultScrimAlpha;
+ } else {
+ mBehindAlpha = behindFraction * mDefaultScrimAlpha;
+ mNotificationsAlpha = mBehindAlpha;
+ }
+ mInFrontAlpha = 0;
+ } else if (mState == ScrimState.BUBBLE_EXPANDED) {
// Darken scrim as you pull down the shade when unlocked
float behindFraction = getInterpolatedFraction();
behindFraction = (float) Math.pow(behindFraction, 0.8f);
@@ -573,27 +601,45 @@
// Either darken of make the scrim transparent when you
// pull down the shade
float interpolatedFract = getInterpolatedFraction();
- float alphaBehind = mState.getBehindAlpha();
+ float stateBehind = mClipsQsScrim ? mState.getNotifAlpha() : mState.getBehindAlpha();
+ float backAlpha;
if (mDarkenWhileDragging) {
- mBehindAlpha = MathUtils.lerp(mDefaultScrimAlpha, alphaBehind,
+ backAlpha = MathUtils.lerp(mDefaultScrimAlpha, stateBehind,
interpolatedFract);
- mInFrontAlpha = mState.getFrontAlpha();
} else {
- mBehindAlpha = MathUtils.lerp(0 /* start */, alphaBehind,
+ backAlpha = MathUtils.lerp(0 /* start */, stateBehind,
interpolatedFract);
- mInFrontAlpha = mState.getFrontAlpha();
}
- mBehindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
- mState.getBehindTint(), interpolatedFract);
+ mInFrontAlpha = mState.getFrontAlpha();
+ int backTint;
+ if (mClipsQsScrim) {
+ backTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getNotifTint(),
+ mState.getNotifTint(), interpolatedFract);
+ } else {
+ backTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
+ mState.getBehindTint(), interpolatedFract);
+ }
if (mQsExpansion > 0) {
- mBehindAlpha = MathUtils.lerp(mBehindAlpha, mDefaultScrimAlpha, mQsExpansion);
- mBehindTint = ColorUtils.blendARGB(mBehindTint,
- ScrimState.SHADE_LOCKED.getBehindTint(), mQsExpansion);
+ backAlpha = MathUtils.lerp(backAlpha, mDefaultScrimAlpha, mQsExpansion);
+ int stateTint = mClipsQsScrim ? ScrimState.SHADE_LOCKED.getNotifTint()
+ : ScrimState.SHADE_LOCKED.getBehindTint();
+ backTint = ColorUtils.blendARGB(backTint, stateTint, mQsExpansion);
+ }
+ if (mClipsQsScrim) {
+ mNotificationsAlpha = backAlpha;
+ mNotificationsTint = backTint;
+ mBehindAlpha = 1;
+ mBehindTint = Color.BLACK;
+ } else {
+ mBehindAlpha = backAlpha;
+ mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
+ mBehindTint = backTint;
}
}
- if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha)) {
+ if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha) || isNaN(mNotificationsAlpha)) {
throw new IllegalStateException("Scrim opacity is NaN for state: " + mState
- + ", front: " + mInFrontAlpha + ", back: " + mBehindAlpha);
+ + ", front: " + mInFrontAlpha + ", back: " + mBehindAlpha + ", notif: "
+ + mNotificationsAlpha);
}
}
@@ -606,7 +652,7 @@
setOrAdaptCurrentAnimation(mNotificationsScrim);
setOrAdaptCurrentAnimation(mScrimInFront);
setOrAdaptCurrentAnimation(mScrimForBubble);
- dispatchScrimState(mScrimBehind.getViewAlpha());
+ dispatchBackScrimState(mScrimBehind.getViewAlpha());
// Reset wallpaper timeout if it's already timeout like expanding panel while PULSING
// and docking.
@@ -693,10 +739,10 @@
&& !mBlankScreen;
mScrimInFront.setColors(mColors, animateScrimInFront);
- mScrimBehind.setColors(mColors, animateScrimNotifications);
+ mScrimBehind.setColors(mColors, animateBehindScrim);
mNotificationsScrim.setColors(mColors, animateScrimNotifications);
- dispatchScrimState(mScrimBehind.getViewAlpha());
+ dispatchBackScrimState(mScrimBehind.getViewAlpha());
}
// We want to override the back scrim opacity for the AOD state
@@ -723,15 +769,21 @@
dispatchScrimsVisible();
}
- private void dispatchScrimState(float alpha) {
+ private void dispatchBackScrimState(float alpha) {
+ // When clipping QS, the notification scrim is the one that feels behind.
+ // mScrimBehind will be drawing black and its opacity will always be 1.
+ if (mClipsQsScrim && mQsBottomVisible) {
+ alpha = mNotificationsAlpha;
+ }
mScrimStateListener.accept(mState, alpha, mScrimInFront.getColors());
}
private void dispatchScrimsVisible() {
+ final ScrimView backScrim = mClipsQsScrim ? mNotificationsScrim : mScrimBehind;
final int currentScrimVisibility;
- if (mScrimInFront.getViewAlpha() == 1 || mScrimBehind.getViewAlpha() == 1) {
+ if (mScrimInFront.getViewAlpha() == 1 || backScrim.getViewAlpha() == 1) {
currentScrimVisibility = OPAQUE;
- } else if (mScrimInFront.getViewAlpha() == 0 && mScrimBehind.getViewAlpha() == 0) {
+ } else if (mScrimInFront.getViewAlpha() == 0 && backScrim.getViewAlpha() == 0) {
currentScrimVisibility = TRANSPARENT;
} else {
currentScrimVisibility = SEMI_TRANSPARENT;
@@ -859,7 +911,7 @@
} else if (scrim == mScrimBehind) {
return mBehindTint;
} else if (scrim == mNotificationsScrim) {
- return Color.TRANSPARENT;
+ return mNotificationsTint;
} else if (scrim == mScrimForBubble) {
return mBubbleTint;
} else {
@@ -917,9 +969,11 @@
if (mState == ScrimState.UNLOCKED) {
mInFrontTint = Color.TRANSPARENT;
mBehindTint = mState.getBehindTint();
+ mNotificationsTint = mState.getNotifTint();
mBubbleTint = Color.TRANSPARENT;
updateScrimColor(mScrimInFront, mInFrontAlpha, mInFrontTint);
updateScrimColor(mScrimBehind, mBehindAlpha, mBehindTint);
+ updateScrimColor(mNotificationsScrim, mNotificationsAlpha, mNotificationsTint);
if (mScrimForBubble != null) {
updateScrimColor(mScrimForBubble, mBubbleAlpha, mBubbleTint);
}
@@ -964,7 +1018,7 @@
}
if (scrim == mScrimBehind) {
- dispatchScrimState(alpha);
+ dispatchBackScrimState(alpha);
}
final boolean wantsAlphaUpdate = alpha != currentAlpha;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index a9774d8..1469cda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -22,7 +22,7 @@
import androidx.annotation.Nullable;
import com.android.systemui.dock.DockManager;
-import com.android.systemui.statusbar.ScrimView;
+import com.android.systemui.scrim.ScrimView;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
/**
@@ -80,11 +80,16 @@
}
mFrontTint = Color.BLACK;
mBehindTint = Color.BLACK;
+ mNotifTint = mClipQsScrim ? Color.BLACK : Color.TRANSPARENT;
mBubbleTint = Color.TRANSPARENT;
mFrontAlpha = 0;
- mBehindAlpha = mScrimBehindAlphaKeyguard;
+ mBehindAlpha = mClipQsScrim ? 1 : mScrimBehindAlphaKeyguard;
+ mNotifAlpha = mClipQsScrim ? mScrimBehindAlphaKeyguard : 0;
mBubbleAlpha = 0;
+ if (mClipQsScrim) {
+ updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+ }
}
},
@@ -105,7 +110,10 @@
BOUNCER {
@Override
public void prepare(ScrimState previousState) {
- mBehindAlpha = mDefaultScrimAlpha;
+ mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
+ mBehindTint = mClipQsScrim ? Color.BLACK : Color.TRANSPARENT;
+ mNotifAlpha = mClipQsScrim ? mDefaultScrimAlpha : 0;
+ mNotifTint = Color.TRANSPARENT;
mFrontAlpha = 0f;
mBubbleAlpha = 0f;
}
@@ -126,10 +134,15 @@
SHADE_LOCKED {
@Override
public void prepare(ScrimState previousState) {
- mBehindAlpha = mDefaultScrimAlpha;
+ mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
+ mNotifAlpha = 1f;
mBubbleAlpha = 0f;
mFrontAlpha = 0f;
mBehindTint = Color.BLACK;
+
+ if (mClipQsScrim) {
+ updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+ }
}
// to make sure correct color is returned before "prepare" is called
@@ -224,7 +237,8 @@
@Override
public void prepare(ScrimState previousState) {
// State that UI will sync to.
- mBehindAlpha = 0;
+ mBehindAlpha = mClipQsScrim ? 1 : 0;
+ mNotifAlpha = 0;
mFrontAlpha = 0;
mBubbleAlpha = 0;
@@ -253,6 +267,10 @@
mBubbleTint = Color.BLACK;
mBlankScreen = true;
}
+
+ if (mClipQsScrim) {
+ updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+ }
}
},
@@ -264,7 +282,7 @@
public void prepare(ScrimState previousState) {
mFrontTint = Color.TRANSPARENT;
mBehindTint = Color.TRANSPARENT;
- mBubbleTint = Color.TRANSPARENT;
+ mBubbleTint = Color.BLACK;
mFrontAlpha = 0f;
mBehindAlpha = mDefaultScrimAlpha;
@@ -279,12 +297,14 @@
int mFrontTint = Color.TRANSPARENT;
int mBehindTint = Color.TRANSPARENT;
int mBubbleTint = Color.TRANSPARENT;
+ int mNotifTint = Color.TRANSPARENT;
boolean mAnimateChange = true;
float mAodFrontScrimAlpha;
float mFrontAlpha;
float mBehindAlpha;
float mBubbleAlpha;
+ float mNotifAlpha;
float mScrimBehindAlphaKeyguard;
float mDefaultScrimAlpha;
@@ -301,6 +321,7 @@
boolean mWakeLockScreenSensorActive;
boolean mKeyguardFadingAway;
long mKeyguardFadingAwayDuration;
+ boolean mClipQsScrim;
public void init(ScrimView scrimInFront, ScrimView scrimBehind, ScrimView scrimForBubble,
DozeParameters dozeParameters, DockManager dockManager) {
@@ -325,6 +346,10 @@
return mBehindAlpha;
}
+ public float getNotifAlpha() {
+ return mNotifAlpha;
+ }
+
public float getBubbleAlpha() {
return mBubbleAlpha;
}
@@ -337,6 +362,10 @@
return mBehindTint;
}
+ public int getNotifTint() {
+ return mNotifTint;
+ }
+
public int getBubbleTint() {
return mBubbleTint;
}
@@ -406,4 +435,8 @@
mKeyguardFadingAway = fadingAway;
mKeyguardFadingAwayDuration = duration;
}
+
+ public void setClipQsScrim(boolean clipsQsScrim) {
+ mClipQsScrim = clipsQsScrim;
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 026072b..dd9ebfc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -21,7 +21,6 @@
import static android.app.StatusBarManager.WindowType;
import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.containsType;
@@ -163,6 +162,7 @@
import com.android.systemui.fragments.ExtensionFragmentListener;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -180,6 +180,7 @@
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.recents.ScreenPinningRequest;
+import com.android.systemui.scrim.ScrimView;
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.AutoHideUiElement;
@@ -202,7 +203,6 @@
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.PowerButtonReveal;
import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -801,7 +801,8 @@
SystemStatusAnimationScheduler animationScheduler,
PrivacyDotViewController dotViewController,
TunerService tunerService,
- FeatureFlags featureFlags) {
+ FeatureFlags featureFlags,
+ KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
super(context);
mNotificationsController = notificationsController;
mLightBarController = lightBarController;
@@ -1123,6 +1124,8 @@
inflateShelf();
mNotificationIconAreaController.setupShelf(mNotificationShelfController);
mNotificationPanelViewController.addExpansionListener(mWakeUpCoordinator);
+ mNotificationPanelViewController.addExpansionListener(
+ this::dispatchPanelExpansionForKeyguardDismiss);
// Allow plugins to reference DarkIconDispatcher and StatusBarStateController
mPluginDependencyProvider.allowPluginDependency(DarkIconDispatcher.class);
@@ -1139,7 +1142,6 @@
mStatusBarView.setScrimController(mScrimController);
mStatusBarView.setExpansionChangedListeners(mExpansionChangedListeners);
- statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
// CollapsedStatusBarFragment re-inflated PhoneStatusBarView and both of
// mStatusBarView.mExpanded and mStatusBarView.mBouncerShowing are false.
// PhoneStatusBarView's new instance will set to be gone in
@@ -1182,7 +1184,8 @@
new CollapsedStatusBarFragment(
mOngoingCallController,
mAnimationScheduler,
- mDotViewController),
+ mDotViewController,
+ mNotificationIconAreaController),
CollapsedStatusBarFragment.TAG)
.commit();
@@ -1349,6 +1352,38 @@
ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
}
+
+ /**
+ * When swiping up to dismiss the lock screen, the panel expansion goes from 1f to 0f. This
+ * results in the clock/notifications/other content disappearing off the top of the screen.
+ *
+ * We also use the expansion amount to animate in the app/launcher surface from the bottom of
+ * the screen, 'pushing' off the notifications and other content. To do this, we dispatch the
+ * expansion amount to the KeyguardViewMediator if we're in the process of dismissing the
+ * keyguard.
+ */
+ private void dispatchPanelExpansionForKeyguardDismiss(float expansion, boolean trackingTouch) {
+ // Things that mean we're not dismissing the keyguard, and should ignore this expansion:
+ // - Keyguard isn't even visible.
+ // - Keyguard is visible, but can't be dismissed (swiping up will show PIN/password prompt).
+ // - QS is expanded and we're swiping - swiping up now will hide QS, not dismiss the
+ // keyguard.
+ if (!isKeyguardShowing()
+ || !mKeyguardStateController.canDismissLockScreen()
+ || (mNotificationPanelViewController.isQsExpanded() && trackingTouch)) {
+ return;
+ }
+
+ // Otherwise, we should let the keyguard know about this if we're tracking touch, or if we
+ // are already animating the keyguard dismiss (since we will need to either finish or cancel
+ // the animation).
+ if (trackingTouch
+ || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) {
+ mKeyguardStateController.notifyKeyguardDismissAmountChanged(
+ 1f - expansion, trackingTouch);
+ }
+ }
+
@NonNull
@Override
public Lifecycle getLifecycle() {
@@ -2016,9 +2051,12 @@
/** A launch animation was cancelled. */
//TODO: These can / should probably be moved to NotificationPresenter or ShadeController
- public void onLaunchAnimationCancelled() {
- if (!mPresenter.isCollapsing()) {
+ public void onLaunchAnimationCancelled(boolean isLaunchForActivity) {
+ if (mPresenter.isPresenterFullyCollapsed() && !mPresenter.isCollapsing()
+ && isLaunchForActivity) {
onClosingFinished();
+ } else {
+ mShadeController.collapsePanel(true /* animate */);
}
}
@@ -2032,16 +2070,6 @@
}
}
- /** A launch animation timed out. */
- public void onLaunchAnimationTimedOut(boolean isLaunchForActivity) {
- if (mPresenter.isPresenterFullyCollapsed() && !mPresenter.isCollapsing()
- && isLaunchForActivity) {
- onClosingFinished();
- } else {
- mShadeController.collapsePanel(true /* animate */);
- }
- }
-
/** Whether we should animate an activity launch. */
public boolean areLaunchAnimationsEnabled() {
// TODO(b/184121838): Support lock screen launch animations.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index ed63a227..14aeca1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -572,6 +572,11 @@
}
@Override
+ public void blockPanelExpansionFromCurrentTouch() {
+ mNotificationPanelViewController.blockExpansionForCurrentTouch();
+ }
+
+ @Override
public void hide(long startTime, long fadeoutDuration) {
mShowing = false;
mKeyguardStateController.notifyKeyguardState(mShowing,
@@ -584,7 +589,8 @@
long uptimeMillis = SystemClock.uptimeMillis();
long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis);
- if (mStatusBar.isInLaunchTransition() ) {
+ if (mStatusBar.isInLaunchTransition()
+ || mKeyguardStateController.isFlingingToDismissKeyguard()) {
mStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() {
@Override
public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
index 4a56020..b2ab307 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
@@ -43,16 +43,6 @@
override fun onLaunchAnimationCancelled() {
delegate.onLaunchAnimationCancelled()
- statusBar.onLaunchAnimationCancelled()
- }
-
- override fun onLaunchAnimationTimedOut() {
- delegate.onLaunchAnimationTimedOut()
- statusBar.onLaunchAnimationTimedOut(isLaunchForActivity)
- }
-
- override fun onLaunchAnimationAborted() {
- delegate.onLaunchAnimationAborted()
- statusBar.collapsePanelOnMainThread()
+ statusBar.onLaunchAnimationCancelled(isLaunchForActivity)
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 088f947..2b5caf9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -364,7 +364,6 @@
MetricsEvent.ACTION_LS_NOTE,
0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_NOTIFICATION_FALSE_TOUCH);
- mNotificationPanel.showTransientIndication(R.string.notification_tap_again);
ActivatableNotificationView previousView = mNotificationPanel.getActivatedChild();
if (previousView != null) {
previousView.makeInactive(true /* animate */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 24e6db8..4795e8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -38,6 +38,7 @@
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -214,7 +215,8 @@
SystemStatusAnimationScheduler animationScheduler,
PrivacyDotViewController dotViewController,
TunerService tunerService,
- FeatureFlags featureFlags) {
+ FeatureFlags featureFlags,
+ KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
return new StatusBar(
context,
notificationsController,
@@ -300,6 +302,7 @@
animationScheduler,
dotViewController,
tunerService,
- featureFlags);
+ featureFlags,
+ keyguardUnlockAnimationController);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 96473c2..51bb643 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -52,6 +52,18 @@
private val mListeners: MutableList<OngoingCallListener> = mutableListOf()
private val notifListener = object : NotifCollectionListener {
+ // Temporary workaround for b/178406514 for testing purposes.
+ //
+ // b/178406514 means that posting an incoming call notif then updating it to an ongoing call
+ // notif does not work (SysUI never receives the update). This workaround allows us to
+ // trigger the ongoing call chip when an ongoing call notif is *added* rather than
+ // *updated*, allowing us to test the chip.
+ //
+ // TODO(b/183229367): Remove this function override when b/178406514 is fixed.
+ override fun onEntryAdded(entry: NotificationEntry) {
+ onEntryUpdated(entry)
+ }
+
override fun onEntryUpdated(entry: NotificationEntry) {
if (isOngoingCallNotification(entry)) {
ongoingCallInfo = OngoingCallInfo(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index a0edc7c..399c850 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -74,13 +74,11 @@
mBrightnessMirror.setVisibility(View.VISIBLE);
mVisibilityCallback.accept(true);
mNotificationPanel.setPanelAlpha(0, true /* animate */);
- mDepthController.setBrightnessMirrorVisible(true);
}
public void hideMirror() {
mVisibilityCallback.accept(false);
mNotificationPanel.setPanelAlpha(255, true /* animate */);
- mDepthController.setBrightnessMirrorVisible(false);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
index d52ea89..9d667805f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
@@ -28,7 +28,6 @@
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
-import com.android.internal.logging.UiEventLogger;
import com.android.keyguard.KeyguardConstants;
import com.android.keyguard.KeyguardVisibilityHelper;
import com.android.keyguard.dagger.KeyguardUserSwitcherScope;
@@ -36,7 +35,9 @@
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.tiles.UserDetailView;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -48,6 +49,7 @@
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
+import javax.inject.Provider;
/**
* Manages the user switch on the Keyguard that is used for opening the QS user panel.
@@ -67,7 +69,9 @@
private final ScreenLifecycle mScreenLifecycle;
private UserSwitcherController.BaseUserAdapter mAdapter;
private final KeyguardStateController mKeyguardStateController;
+ private final FalsingManager mFalsingManager;
protected final SysuiStatusBarStateController mStatusBarStateController;
+ private final ConfigurationController mConfigurationController;
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
private final KeyguardUserDetailAdapter mUserDetailAdapter;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -76,7 +80,6 @@
// State info for the user switch and keyguard
private int mBarState;
- private float mDarkAmount;
private final StatusBarStateController.StateListener mStatusBarStateListener =
new StatusBarStateController.StateListener() {
@@ -97,6 +100,15 @@
}
};
+ private ConfigurationController.ConfigurationListener
+ mConfigurationListener = new ConfigurationController.ConfigurationListener() {
+
+ @Override
+ public void onUiModeChanged() {
+ updateView(true);
+ }
+ };
+
@Inject
public KeyguardQsUserSwitchController(
UserAvatarView view,
@@ -106,9 +118,11 @@
ScreenLifecycle screenLifecycle,
UserSwitcherController userSwitcherController,
KeyguardStateController keyguardStateController,
+ FalsingManager falsingManager,
+ ConfigurationController configurationController,
SysuiStatusBarStateController statusBarStateController,
DozeParameters dozeParameters,
- UiEventLogger uiEventLogger) {
+ Provider<UserDetailView.Adapter> userDetailViewAdapterProvider) {
super(view);
if (DEBUG) Log.d(TAG, "New KeyguardQsUserSwitchController");
mContext = context;
@@ -117,11 +131,12 @@
mScreenLifecycle = screenLifecycle;
mUserSwitcherController = userSwitcherController;
mKeyguardStateController = keyguardStateController;
+ mFalsingManager = falsingManager;
+ mConfigurationController = configurationController;
mStatusBarStateController = statusBarStateController;
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView,
keyguardStateController, dozeParameters);
- mUserDetailAdapter = new KeyguardUserDetailAdapter(mUserSwitcherController, mContext,
- uiEventLogger);
+ mUserDetailAdapter = new KeyguardUserDetailAdapter(context, userDetailViewAdapterProvider);
}
@Override
@@ -136,6 +151,10 @@
};
mView.setOnClickListener(v -> {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ return;
+ }
+
if (isListAnimating()) {
return;
}
@@ -153,8 +172,6 @@
R.string.accessibility_quick_settings_choose_user_action)));
}
});
-
- updateView(true /* forceUpdate */);
}
@Override
@@ -163,6 +180,8 @@
mAdapter.registerDataSetObserver(mDataSetObserver);
mDataSetObserver.onChanged();
mStatusBarStateController.addCallback(mStatusBarStateListener);
+ mConfigurationController.addCallback(mConfigurationListener);
+ updateView(true /* forceUpdate */);
}
@Override
@@ -171,6 +190,7 @@
mAdapter.unregisterDataSetObserver(mDataSetObserver);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
+ mConfigurationController.removeCallback(mConfigurationListener);
}
public final DataSetObserver mDataSetObserver = new DataSetObserver() {
@@ -304,9 +324,9 @@
}
class KeyguardUserDetailAdapter extends UserSwitcherController.UserDetailAdapter {
- KeyguardUserDetailAdapter(UserSwitcherController userSwitcherController, Context context,
- UiEventLogger uiEventLogger) {
- super(userSwitcherController, context, uiEventLogger);
+ KeyguardUserDetailAdapter(Context context,
+ Provider<UserDetailView.Adapter> userDetailViewAdapterProvider) {
+ super(context, userDetailViewAdapterProvider);
}
@Override
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 692c34c..e7201f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -139,6 +139,38 @@
*/
long calculateGoingToFullShadeDelay();
+ /**
+ * How much (from 0f to 1f) the keyguard is dismissed, either via a swipe gesture or an
+ * animation.
+ */
+ float getDismissAmount();
+
+ /**
+ * Whether the keyguard is being dismissed due to direct user input, rather than a canned
+ * animation.
+ */
+ boolean isDismissingFromSwipe();
+
+ /**
+ * Whether a fling animation is currently playing on the keyguard, either to dismiss it or to
+ * cancel dismissing it.
+ */
+ boolean isFlingingToDismissKeyguard();
+
+ /**
+ * Whether a fling animation is currently playing on the keyguard, either to dismiss it or to
+ * cancel dismissing it, and that animation started during a swipe gesture. Fling animations
+ * can also be started without a swipe (e.g. activity launch from lock screen notification), so
+ * this is a way to tell them apart for animation purposes.
+ */
+ boolean isFlingingToDismissKeyguardDuringSwipeGesture();
+
+ /**
+ * Whether a fling animation is currently playing on the keyguard to cancel dismissing it, after
+ * the user released their finger during a swipe gesture.
+ */
+ boolean isSnappingKeyguardBackAfterSwipe();
+
/** **/
default void setLaunchTransitionFadingAway(boolean b) {}
/** **/
@@ -149,6 +181,28 @@
default void notifyKeyguardState(boolean showing, boolean occluded) {}
/**
+ * Updates the keyguard state to reflect that it's in the process of being dismissed, either by
+ * a swipe gesture on the lock screen or by a canned animation.
+ *
+ * @param dismissAmount 0f means we're not dismissed at all, 1f means we have been completely
+ * swiped away.
+ * @param dismissingFromTouch True if this change was caused by direct user interaction, false
+ * if it's due to an animation.
+ */
+ default void notifyKeyguardDismissAmountChanged(
+ float dismissAmount, boolean dismissingFromTouch) {}
+
+ /**
+ * Updates the keyguard state to reflect that a dismiss fling gesture has started.
+ *
+ * @param dismiss Whether we're flinging to dismiss (upward) or to cancel a dismiss gesture.
+ */
+ void notifyPanelFlingStart(boolean dismiss);
+
+ /** Updates the keyguard state to reflect that a dismiss fling gesture has ended. */
+ void notifyPanelFlingEnd();
+
+ /**
* Callback for authentication events.
*/
interface Callback {
@@ -173,5 +227,11 @@
* Triggered when the device was just unlocked and the lock screen is being dismissed.
*/
default void onKeyguardFadingAwayChanged() {}
+
+ /**
+ * Triggered when the keyguard dismiss amount has changed, via either a swipe gesture or an
+ * animation.
+ */
+ default void onKeyguardDismissAmountChanged() {}
}
}
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 7f4eec7..e69c1f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -70,6 +70,28 @@
private boolean mDebugUnlocked = false;
private boolean mFaceAuthEnabled;
+ private float mDismissAmount = 0f;
+ private boolean mDismissingFromTouch = false;
+
+ /**
+ * Whether the panel is currently flinging to a collapsed state, which means we're dismissing
+ * the keyguard.
+ */
+ private boolean mFlingingToDismissKeyguard = false;
+
+ /**
+ * Whether the panel is currently flinging to a collapsed state, which means we're dismissing
+ * the keyguard, and the fling started during a swipe gesture. This means that we need to take
+ * over the gesture and animate the rest of the way dismissed.
+ */
+ private boolean mFlingingToDismissKeyguardDuringSwipeGesture = false;
+
+ /**
+ * Whether the panel is currently flinging to an expanded state, which means we cancelled the
+ * dismiss gesture and are snapping back to the keyguard state.
+ */
+ private boolean mSnappingKeyguardBackAfterSwipe = false;
+
/**
*/
@Inject
@@ -241,11 +263,59 @@
}
@Override
+ public boolean isFlingingToDismissKeyguard() {
+ return mFlingingToDismissKeyguard;
+ }
+
+ @Override
+ public boolean isFlingingToDismissKeyguardDuringSwipeGesture() {
+ return mFlingingToDismissKeyguardDuringSwipeGesture;
+ }
+
+ @Override
+ public boolean isSnappingKeyguardBackAfterSwipe() {
+ return mSnappingKeyguardBackAfterSwipe;
+ }
+
+ @Override
+ public float getDismissAmount() {
+ return mDismissAmount;
+ }
+
+ @Override
+ public boolean isDismissingFromSwipe() {
+ return mDismissingFromTouch;
+ }
+
+ @Override
public void notifyKeyguardGoingAway(boolean keyguardGoingAway) {
mKeyguardGoingAway = keyguardGoingAway;
}
@Override
+ public void notifyPanelFlingEnd() {
+ mFlingingToDismissKeyguard = false;
+ mFlingingToDismissKeyguardDuringSwipeGesture = false;
+ mSnappingKeyguardBackAfterSwipe = false;
+ }
+
+ @Override
+ public void notifyPanelFlingStart(boolean flingToDismiss) {
+ mFlingingToDismissKeyguard = flingToDismiss;
+ mFlingingToDismissKeyguardDuringSwipeGesture =
+ flingToDismiss && mDismissingFromTouch;
+ mSnappingKeyguardBackAfterSwipe = !flingToDismiss;
+ }
+
+ @Override
+ public void notifyKeyguardDismissAmountChanged(float dismissAmount,
+ boolean dismissingFromTouch) {
+ mDismissAmount = dismissAmount;
+ mDismissingFromTouch = dismissingFromTouch;
+ new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardDismissAmountChanged);
+ }
+
+ @Override
public void setLaunchTransitionFadingAway(boolean fadingAway) {
mLaunchTransitionFadingAway = fadingAway;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index a3fd92f..d86ef32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -112,6 +112,7 @@
private final TextView.OnEditorActionListener mEditorActionHandler;
private final NotificationRemoteInputManager mRemoteInputManager;
private final List<OnFocusChangeListener> mEditTextFocusChangeListeners = new ArrayList<>();
+ private final List<OnSendRemoteInputListener> mOnSendListeners = new ArrayList<>();
private RemoteEditText mEditText;
private ImageButton mSendButton;
private GradientDrawable mContentBackground;
@@ -357,6 +358,9 @@
private void sendRemoteInput(Intent intent) {
if (mBouncerChecker != null && mBouncerChecker.showBouncerIfNecessary()) {
mEditText.hideIme();
+ for (OnSendRemoteInputListener listener : mOnSendListeners) {
+ listener.onSendRequestBounced();
+ }
return;
}
@@ -370,6 +374,10 @@
mController.remoteInputSent(mEntry);
mEntry.setHasSentReply();
+ for (OnSendRemoteInputListener listener : mOnSendListeners) {
+ listener.onSendRemoteInput();
+ }
+
// Tell ShortcutManager that this package has been "activated". ShortcutManager
// will reset the throttling for this package.
// Strictly speaking, the intent receiver may be different from the notification publisher,
@@ -754,6 +762,27 @@
}
}
+ /** Registers a listener for send events on this RemoteInputView */
+ public void addOnSendRemoteInputListener(OnSendRemoteInputListener listener) {
+ mOnSendListeners.add(listener);
+ }
+
+ /** Removes a previously-added listener for send events on this RemoteInputView */
+ public void removeOnSendRemoteInputListener(OnSendRemoteInputListener listener) {
+ mOnSendListeners.remove(listener);
+ }
+
+ /** Listener for send events */
+ public interface OnSendRemoteInputListener {
+ /** Invoked when the remote input has been sent successfully. */
+ void onSendRemoteInput();
+ /**
+ * Invoked when the user had requested to send the remote input, but authentication was
+ * required and the bouncer was shown instead.
+ */
+ void onSendRequestBounced();
+ }
+
/** Handler for button click on send action in IME. */
private class EditorActionHandler implements TextView.OnEditorActionListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 83558cb..5c44017 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -78,6 +78,7 @@
import java.util.List;
import javax.inject.Inject;
+import javax.inject.Provider;
/**
* Keeps a list of all users on the device for user switching.
@@ -128,14 +129,14 @@
@Main Handler handler, ActivityStarter activityStarter,
BroadcastDispatcher broadcastDispatcher, UiEventLogger uiEventLogger,
TelephonyListenerManager telephonyListenerManager,
- IActivityTaskManager activityTaskManager) {
+ IActivityTaskManager activityTaskManager, UserDetailAdapter userDetailAdapter) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
mTelephonyListenerManager = telephonyListenerManager;
mActivityTaskManager = activityTaskManager;
mUiEventLogger = uiEventLogger;
mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(mUiEventLogger);
- mUserDetailAdapter = new UserDetailAdapter(this, mContext, mUiEventLogger);
+ mUserDetailAdapter = userDetailAdapter;
if (!UserManager.isGuestUserEphemeral()) {
mGuestResumeSessionReceiver.register(mBroadcastDispatcher);
}
@@ -577,11 +578,13 @@
pw.println("mSimpleUserSwitcher=" + mSimpleUserSwitcher);
}
- public String getCurrentUserName(Context context) {
+ /** Returns the name of the current user of the phone. */
+ public String getCurrentUserName() {
if (mUsers.isEmpty()) return null;
UserRecord item = mUsers.get(0);
if (item == null || item.info == null) return null;
- if (item.isGuest) return context.getString(com.android.settingslib.R.string.guest_nickname);
+ if (item.isGuest) return mContext.getString(
+ com.android.settingslib.R.string.guest_nickname);
return item.info.name;
}
@@ -787,15 +790,14 @@
public static class UserDetailAdapter implements DetailAdapter {
private final Intent USER_SETTINGS_INTENT = new Intent(Settings.ACTION_USER_SETTINGS);
- private final UserSwitcherController mUserSwitcherController;
private final Context mContext;
- private final UiEventLogger mUiEventLogger;
+ private final Provider<UserDetailView.Adapter> mUserDetailViewAdapterProvider;
- UserDetailAdapter(UserSwitcherController userSwitcherController, Context context,
- UiEventLogger uiEventLogger) {
- mUserSwitcherController = userSwitcherController;
+ @Inject
+ UserDetailAdapter(Context context,
+ Provider<UserDetailView.Adapter> userDetailViewAdapterProvider) {
mContext = context;
- mUiEventLogger = uiEventLogger;
+ mUserDetailViewAdapterProvider = userDetailViewAdapterProvider;
}
@Override
@@ -808,7 +810,7 @@
UserDetailView v;
if (!(convertView instanceof UserDetailView)) {
v = UserDetailView.inflate(context, parent, false);
- v.createAndSetAdapter(mUserSwitcherController, mUiEventLogger);
+ v.setAdapter(mUserDetailViewAdapterProvider.get());
} else {
v = (UserDetailView) convertView;
}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 5702028..755372b 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -299,7 +299,7 @@
// but cause crash when call notifyAsUser(). Here we return directly for USER_NULL, and
// leave all notifications belong to removed user to NotificationManagerService, the latter
// will remove all notifications of the removed user when handles user stopped broadcast.
- if (isAutomotive() && vol.getMountUserId() == UserHandle.USER_NULL) {
+ if (vol.getMountUserId() == UserHandle.USER_NULL) {
Log.d(TAG, "Ignore public volume state change event of removed user");
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/DualHeightHorizontalLinearLayout.kt b/packages/SystemUI/src/com/android/systemui/util/DualHeightHorizontalLinearLayout.kt
new file mode 100644
index 0000000..0e04871
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/DualHeightHorizontalLinearLayout.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util
+
+import android.content.Context
+import android.content.res.Configuration
+import android.util.AttributeSet
+import android.util.DisplayMetrics
+import android.util.TypedValue
+import android.widget.LinearLayout
+import android.widget.TextView
+import com.android.systemui.R
+
+/**
+ * Horizontal [LinearLayout] to contain some text.
+ *
+ * The height of this container can alternate between two different heights, depending on whether
+ * the text takes one line or more.
+ *
+ * When the text takes multiple lines, it will use the values in the regular attributes (`padding`,
+ * `layout_height`). The single line behavior must be set in XML.
+ *
+ * XML attributes for single line behavior:
+ * * `systemui:textViewId`: set the id for the [TextView] that determines the height of the
+ * container
+ * * `systemui:singleLineHeight`: sets the height of the view when the text takes up only one line.
+ * By default, it will use [getMinimumHeight].
+ * * `systemui:singleLineVerticalPadding`: sets the padding (top and bottom) when then text takes up
+ * only one line. By default, it is 0.
+ *
+ * All dimensions are updated when configuration changes.
+ */
+class DualHeightHorizontalLinearLayout @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttrs: Int = 0,
+ defStyleRes: Int = 0
+) : LinearLayout(context, attrs, defStyleAttrs, defStyleRes) {
+
+ private val singleLineHeightValue: TypedValue?
+ private var singleLineHeightPx = 0
+
+ private val singleLineVerticalPaddingValue: TypedValue?
+ private var singleLineVerticalPaddingPx = 0
+
+ private val textViewId: Int
+ private var textView: TextView? = null
+
+ private val displayMetrics: DisplayMetrics
+ get() = context.resources.displayMetrics
+
+ private var initialPadding = mPaddingTop // All vertical padding is the same
+
+ init {
+ if (orientation != HORIZONTAL) {
+ throw IllegalStateException("This view should always have horizontal orientation")
+ }
+
+ val ta = context.obtainStyledAttributes(
+ attrs,
+ R.styleable.DualHeightHorizontalLinearLayout, defStyleAttrs, defStyleRes
+ )
+
+ val tempHeight = TypedValue()
+ singleLineHeightValue = if (
+ ta.hasValue(R.styleable.DualHeightHorizontalLinearLayout_singleLineHeight)
+ ) {
+ ta.getValue(R.styleable.DualHeightHorizontalLinearLayout_singleLineHeight, tempHeight)
+ tempHeight
+ } else {
+ null
+ }
+
+ val tempPadding = TypedValue()
+ singleLineVerticalPaddingValue = if (
+ ta.hasValue(R.styleable.DualHeightHorizontalLinearLayout_singleLineVerticalPadding)
+ ) {
+ ta.getValue(
+ R.styleable.DualHeightHorizontalLinearLayout_singleLineVerticalPadding,
+ tempPadding
+ )
+ tempPadding
+ } else {
+ null
+ }
+
+ textViewId = ta.getResourceId(R.styleable.DualHeightHorizontalLinearLayout_textViewId, 0)
+
+ ta.recycle()
+ }
+
+ init {
+ updateResources()
+ }
+
+ override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {
+ super.setPadding(left, top, right, bottom)
+ initialPadding = top
+ }
+
+ override fun setPaddingRelative(start: Int, top: Int, end: Int, bottom: Int) {
+ super.setPaddingRelative(start, top, end, bottom)
+ initialPadding = top
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ textView?.let { tv ->
+ if (tv.lineCount < 2) {
+ setMeasuredDimension(measuredWidth, singleLineHeightPx)
+ mPaddingBottom = 0
+ mPaddingTop = 0
+ } else {
+ mPaddingBottom = initialPadding
+ mPaddingTop = initialPadding
+ }
+ }
+ }
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ textView = findViewById(textViewId)
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration?) {
+ super.onConfigurationChanged(newConfig)
+ updateResources()
+ }
+
+ override fun setOrientation(orientation: Int) {
+ if (orientation == VERTICAL) {
+ throw IllegalStateException("This view should always have horizontal orientation")
+ }
+ super.setOrientation(orientation)
+ }
+
+ private fun updateResources() {
+ updateDimensionValue(singleLineHeightValue, minimumHeight, ::singleLineHeightPx::set)
+ updateDimensionValue(singleLineVerticalPaddingValue, 0, ::singleLineVerticalPaddingPx::set)
+ }
+
+ private inline fun updateDimensionValue(
+ tv: TypedValue?,
+ defaultValue: Int,
+ propertySetter: (Int) -> Unit
+ ) {
+ val value = tv?.let {
+ if (it.resourceId != 0) {
+ context.resources.getDimensionPixelSize(it.resourceId)
+ } else {
+ it.getDimension(displayMetrics).toInt()
+ }
+ } ?: defaultValue
+ propertySetter(value)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index b823534..b955455 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -63,11 +63,11 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
index 141b9f7..39a8bd9 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -32,8 +32,9 @@
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
import com.android.wm.shell.common.annotations.ShellMainThread;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
+import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm;
+import com.android.wm.shell.startingsurface.tv.TvStartingWindowTypeAlgorithm;
import com.android.wm.shell.transition.Transitions;
import dagger.Module;
@@ -80,4 +81,14 @@
displayImeController, transactionPool, shellTaskOrganizer, syncQueue,
taskStackListener, transitions, mainExecutor, sfVsyncAnimationHandler);
}
+
+ //
+ // Starting Windows (Splash Screen)
+ //
+
+ @WMSingleton
+ @Provides
+ static StartingWindowTypeAlgorithm provideStartingWindowTypeAlgorithm() {
+ return new TvStartingWindowTypeAlgorithm();
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 74077a2..81bb819 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -236,14 +236,6 @@
oneHanded.registerTransitionCallback(new OneHandedTransitionCallback() {
@Override
- public void onStartTransition(boolean isEntering) {
- mSysUiMainExecutor.execute(() -> {
- mSysUiState.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE,
- true).commitUpdate(DEFAULT_DISPLAY);
- });
- }
-
- @Override
public void onStartFinished(Rect bounds) {
mSysUiMainExecutor.execute(() -> {
mSysUiState.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index f96d344..26b68af 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -72,6 +72,7 @@
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.startingsurface.StartingWindowController;
+import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm;
import com.android.wm.shell.transition.ShellTransitions;
import com.android.wm.shell.transition.Transitions;
@@ -189,12 +190,13 @@
TaskStackListenerImpl taskStackListener,
UiEventLogger uiEventLogger,
ShellTaskOrganizer organizer,
+ DisplayController displayController,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler) {
return Optional.of(BubbleController.create(context, null /* synchronizer */,
floatingContentCoordinator, statusBarService, windowManager,
windowManagerShellWrapper, launcherApps, taskStackListener,
- uiEventLogger, organizer, mainExecutor, mainHandler));
+ uiEventLogger, organizer, displayController, mainExecutor, mainHandler));
}
//
@@ -381,8 +383,10 @@
@WMSingleton
@Provides
static StartingWindowController provideStartingWindowController(Context context,
- @ShellSplashscreenThread ShellExecutor splashScreenExecutor, TransactionPool pool) {
- return new StartingWindowController(context, splashScreenExecutor, pool);
+ @ShellSplashscreenThread ShellExecutor splashScreenExecutor,
+ StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, TransactionPool pool) {
+ return new StartingWindowController(context, splashScreenExecutor,
+ startingWindowTypeAlgorithm, pool);
}
//
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 743dd46..36fd9be 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -54,6 +54,8 @@
import com.android.wm.shell.pip.phone.PipController;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.pip.phone.PipTouchHandler;
+import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm;
+import com.android.wm.shell.startingsurface.phone.PhoneStartingWindowTypeAlgorithm;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
@@ -229,4 +231,14 @@
menuController, pipSnapAlgorithm, pipTransitionController,
floatingContentCoordinator);
}
+
+ //
+ // Starting Windows (Splash Screen)
+ //
+
+ @WMSingleton
+ @Provides
+ static StartingWindowTypeAlgorithm provideStartingWindowTypeAlgorithm() {
+ return new PhoneStartingWindowTypeAlgorithm();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 263a75c..39ebe68 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -41,8 +41,11 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.IntentStarter;
import com.android.systemui.plugins.ClockPlugin;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarState;
@@ -107,6 +110,10 @@
SmartspaceView mSmartspaceView;
@Mock
SystemUIFactory mSystemUIFactory;
+ @Mock
+ ActivityStarter mActivityStarter;
+ @Mock
+ FalsingManager mFalsingManager;
private KeyguardClockSwitchController mController;
private View mStatusArea;
@@ -143,7 +150,9 @@
mExecutor,
mBatteryController,
mConfigurationController,
- mSystemUIFactory
+ mSystemUIFactory,
+ mActivityStarter,
+ mFalsingManager
);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
@@ -152,7 +161,6 @@
mStatusArea = new View(getContext());
when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(mStatusArea);
when(mSmartspaceDataProvider.getView(any())).thenReturn(mSmartspaceView);
-
}
@Test
@@ -264,5 +272,9 @@
public void setPrimaryTextColor(int color) { }
public void setDozeAmount(float amount) { }
+
+ public void setIntentStarter(IntentStarter intentStarter) { }
+
+ public void setFalsingManager(FalsingManager falsingManager) { }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java
index 4d52650..42314bf 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java
@@ -29,6 +29,7 @@
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.ViewGroup;
import android.widget.FrameLayout;
@@ -49,7 +50,6 @@
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class KeyguardHostViewControllerTest extends SysuiTestCase {
-
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -68,14 +68,21 @@
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
+ private TestableResources mTestableResources;
private KeyguardHostViewController mKeyguardHostViewController;
@Before
public void setup() {
- mContext.ensureTestableResources();
+ mTestableResources = mContext.getOrCreateTestableResources();
mKeyguardHostView = new KeyguardHostView(mContext);
+ // Explicitly disable one handed keyguard.
+ mTestableResources.addOverride(
+ R.bool.can_use_one_handed_bouncer, false);
+ mTestableResources.addOverride(
+ com.android.internal.R.bool.config_enableOneHandedKeyguard, false);
+
when(mKeyguardSecurityContainerControllerFactory.create(any(
KeyguardSecurityContainer.SecurityCallback.class)))
.thenReturn(mKeyguardSecurityContainerController);
@@ -106,7 +113,7 @@
mKeyguardHostView.setLayoutParams(lp);
// Set initial gravity
- mContext.getOrCreateTestableResources().addOverride(R.integer.keyguard_host_view_gravity,
+ mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
Gravity.CENTER);
// Kick off the initial pass...
@@ -116,7 +123,7 @@
Gravity.CENTER);
// Now simulate a config change
- mContext.getOrCreateTestableResources().addOverride(R.integer.keyguard_host_view_gravity,
+ mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
mKeyguardHostViewController.updateResources();
@@ -126,6 +133,43 @@
}
@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);
+ mTestableResources.addOverride(
+ com.android.internal.R.bool.config_enableOneHandedKeyguard, false);
+
+ mKeyguardHostViewController.init();
+ assertEquals(
+ ((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
+ Gravity.CENTER);
+
+ // And enable
+ mTestableResources.addOverride(
+ R.bool.can_use_one_handed_bouncer, true);
+ mTestableResources.addOverride(
+ com.android.internal.R.bool.config_enableOneHandedKeyguard, true);
+
+ mKeyguardHostViewController.updateResources();
+ assertEquals(
+ ((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
+ Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
+ }
+
+ @Test
public void testUpdateKeyguardPositionDelegatesToSecurityContainer() {
mKeyguardHostViewController.updateKeyguardPosition(1.0f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
index 28cc580..0de257a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
@@ -16,6 +16,9 @@
package com.android.systemui.accessibility.floatingmenu;
+import static android.view.View.OVER_SCROLL_ALWAYS;
+import static android.view.View.OVER_SCROLL_NEVER;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -437,6 +440,30 @@
action -> action.getId() == R.id.action_move_to_edge_and_hide)).isTrue();
}
+ @Test
+ public void onTargetsChanged_exceedAvailableHeight_overScrollAlways() {
+ final RecyclerView listView = new RecyclerView(mContext);
+ final AccessibilityFloatingMenuView menuView =
+ spy(new AccessibilityFloatingMenuView(mContext, listView));
+ doReturn(true).when(menuView).hasExceededMaxLayoutHeight();
+
+ menuView.onTargetsChanged(mTargets);
+
+ assertThat(listView.getOverScrollMode()).isEqualTo(OVER_SCROLL_ALWAYS);
+ }
+
+ @Test
+ public void onTargetsChanged_notExceedAvailableHeight_overScrollNever() {
+ final RecyclerView listView = new RecyclerView(mContext);
+ final AccessibilityFloatingMenuView menuView =
+ spy(new AccessibilityFloatingMenuView(mContext, listView));
+ doReturn(false).when(menuView).hasExceededMaxLayoutHeight();
+
+ mMenuView.onTargetsChanged(mTargets);
+
+ assertThat(mListView.getOverScrollMode()).isEqualTo(OVER_SCROLL_NEVER);
+ }
+
@After
public void tearDown() {
mInterceptMotionEvent = null;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
index 6420c4e..c023610 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
@@ -106,12 +106,12 @@
}
@Test
- fun abortsIfNoOpeningWindowIsFound() {
+ fun cancelsIfNoOpeningWindowIsFound() {
val runner = activityLaunchAnimator.createRunner(controller)
runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback)
waitForIdleSync()
- verify(controller).onLaunchAnimationAborted()
+ verify(controller).onLaunchAnimationCancelled()
verify(controller, never()).onLaunchAnimationStart(anyBoolean())
}
@@ -177,12 +177,4 @@
override fun onLaunchAnimationCancelled() {
assertOnMainThread()
}
-
- override fun onLaunchAnimationTimedOut() {
- assertOnMainThread()
- }
-
- override fun onLaunchAnimationAborted() {
- assertOnMainThread()
- }
}
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 3fe8cee..1b464a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -50,7 +50,9 @@
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.os.Bundle;
+import android.os.RemoteException;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
@@ -66,6 +68,7 @@
import org.junit.runner.RunWith;
import org.mockito.AdditionalMatchers;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -100,12 +103,13 @@
private FaceManager mFaceManager;
@Mock
private UdfpsController mUdfpsController;
+ @Captor
+ ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mAuthenticatorsRegisteredCaptor;
private TestableAuthController mAuthController;
-
@Before
- public void setup() {
+ public void setup() throws RemoteException {
MockitoAnnotations.initMocks(this);
TestableContext context = spy(mContext);
@@ -148,6 +152,9 @@
() -> mUdfpsController);
mAuthController.start();
+ verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
+ mAuthenticatorsRegisteredCaptor.capture());
+ mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(props);
}
// Callback tests
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 725f0e6..40c4851 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -24,7 +24,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.content.res.Resources;
import android.content.res.TypedArray;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.SensorProperties;
@@ -40,6 +39,7 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
import androidx.test.filters.SmallTest;
@@ -85,8 +85,6 @@
// Dependencies
@Mock
- private Resources mResources;
- @Mock
private LayoutInflater mLayoutInflater;
@Mock
private FingerprintManager mFingerprintManager;
@@ -110,6 +108,8 @@
private FalsingManager mFalsingManager;
@Mock
private PowerManager mPowerManager;
+ @Mock
+ private AccessibilityManager mAccessibilityManager;
private FakeExecutor mFgExecutor;
@@ -151,7 +151,6 @@
mFgExecutor = new FakeExecutor(new FakeSystemClock());
mUdfpsController = new UdfpsController(
mContext,
- mResources,
mLayoutInflater,
mFingerprintManager,
mWindowManager,
@@ -163,7 +162,8 @@
mKeyguardUpdateMonitor,
mKeyguardViewMediator,
mFalsingManager,
- mPowerManager);
+ mPowerManager,
+ mAccessibilityManager);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
@@ -174,16 +174,9 @@
when(mBrightnessValues.length()).thenReturn(2);
when(mBrightnessValues.getFloat(0, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(1f);
when(mBrightnessValues.getFloat(1, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(2f);
- when(mResources.obtainTypedArray(com.android.internal.R.array.config_screenBrightnessNits))
- .thenReturn(mBrightnessValues);
when(mBrightnessBacklight.length()).thenReturn(2);
when(mBrightnessBacklight.getFloat(0, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(1f);
when(mBrightnessBacklight.getFloat(1, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(2f);
- when(mResources.obtainTypedArray(
- com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
- .thenReturn(mBrightnessBacklight);
- when(mResources.getIntArray(com.android.internal.R.array.config_screenBrightnessBacklight))
- .thenReturn(new int[]{1, 2});
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
index f077190..bc24445 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
@@ -179,7 +179,23 @@
mFalsingCollector.onTouchEvent(down);
verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class));
- // Up event would normally flush the up event.
+ // Up event would normally flush the up event, but doesn't.
+ mFalsingCollector.onTouchEvent(up);
+ verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class));
+ }
+
+ @Test
+ public void testAvoidDozing() {
+ MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+ MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0);
+
+ when(mStatusBarStateController.isDozing()).thenReturn(true);
+
+ // Nothing passed initially
+ mFalsingCollector.onTouchEvent(down);
+ verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class));
+
+ // Up event would normally flush the up event, but doesn't.
mFalsingCollector.onTouchEvent(up);
verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index fe2103c..724f8a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -42,6 +42,7 @@
when(params.getSelectivelyRegisterSensorsUsingProx()).thenReturn(false);
when(params.singleTapUsesProx()).thenReturn(true);
when(params.longPressUsesProx()).thenReturn(true);
+ when(params.getQuickPickupAodDuration()).thenReturn(500);
doneHolder[0] = true;
return params;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 8eb0e9c..4a9d66c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -35,10 +35,12 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.doze.DozeTriggers.DozingUpdateUiEvent;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.concurrency.FakeThreadFactory;
@@ -76,6 +78,8 @@
private ProximitySensor.ProximityCheck mProximityCheck;
@Mock
private AuthController mAuthController;
+ @Mock
+ private UiEventLogger mUiEventLogger;
private DozeTriggers mTriggers;
private FakeSensorManager mSensors;
@@ -107,7 +111,7 @@
mTriggers = new DozeTriggers(mContext, mHost, config, dozeParameters,
asyncSensorManager, wakeLock, mDockManager, mProximitySensor,
mProximityCheck, mock(DozeLog.class), mBroadcastDispatcher, new FakeSettings(),
- mAuthController, mExecutor);
+ mAuthController, mExecutor, mUiEventLogger);
mTriggers.setDozeMachine(mMachine);
waitForSensorManager();
}
@@ -195,6 +199,40 @@
}
@Test
+ public void testQuickPickup() {
+ // GIVEN device is in doze (screen blank, but running doze sensors)
+ when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+
+ // WHEN quick pick up is triggered
+ mTriggers.onSensor(DozeLog.REASON_SENSOR_QUICK_PICKUP, 100, 100, null);
+
+ // THEN device goes into aod (shows clock with black background)
+ verify(mMachine).requestState(DozeMachine.State.DOZE_AOD);
+
+ // THEN a log is taken that quick pick up was triggered
+ verify(mUiEventLogger).log(DozingUpdateUiEvent.DOZING_UPDATE_QUICK_PICKUP);
+ }
+
+ @Test
+ public void testQuickPickupTimeOutAfterExecutables() {
+ // GIVEN quick pickup is triggered when device is in DOZE
+ when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+ mTriggers.onSensor(DozeLog.REASON_SENSOR_QUICK_PICKUP, 100, 100, null);
+ verify(mMachine).requestState(DozeMachine.State.DOZE_AOD);
+ verify(mMachine, never()).requestState(DozeMachine.State.DOZE);
+
+ // WHEN next executable is run
+ mExecutor.advanceClockToLast();
+ mExecutor.runAllReady();
+
+ // THEN device goes back into DOZE
+ verify(mMachine).requestState(DozeMachine.State.DOZE);
+
+ // THEN a log is taken that wake up timeout expired
+ verify(mUiEventLogger).log(DozingUpdateUiEvent.DOZING_UPDATE_WAKE_TIMEOUT);
+ }
+
+ @Test
public void testOnSensor_Fingerprint() {
final int screenX = 100;
final int screenY = 100;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index b8c37fd..5c87741 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -29,17 +29,13 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
-import android.view.View;
-import com.android.systemui.R;
import androidx.test.filters.SmallTest;
import com.android.internal.widget.LockPatternUtils;
@@ -51,9 +47,9 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.LightRevealScrim;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.DeviceConfigProxyFake;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -84,6 +80,8 @@
private @Mock KeyguardDisplayManager mKeyguardDisplayManager;
private @Mock DozeParameters mDozeParameters;
private @Mock StatusBarStateController mStatusBarStateController;
+ private @Mock KeyguardStateController mKeyguardStateController;
+ private @Mock KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -102,7 +100,8 @@
() -> mStatusBarKeyguardViewManager,
mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor,
mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController,
- mKeyguardDisplayManager, mDozeParameters, mStatusBarStateController);
+ mKeyguardDisplayManager, mDozeParameters, mStatusBarStateController,
+ mKeyguardStateController, () -> mKeyguardUnlockAnimationController);
mViewMediator.start();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
index 730c941..0d67d66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
@@ -19,26 +19,23 @@
import android.testing.AndroidTestingRunner
import android.view.View.GONE
import android.view.View.VISIBLE
+import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.MediaHeaderView
import com.android.systemui.statusbar.phone.KeyguardBypassController
-import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.animation.UniqueObjectHostView
+import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.Mockito.atLeastOnce
-import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -52,51 +49,81 @@
private lateinit var statusBarStateController: SysuiStatusBarStateController
@Mock
private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
- @Mock
- private lateinit var mediaHeaderView: MediaHeaderView
- @Captor
- private lateinit var visibilityListener: ArgumentCaptor<((Boolean) -> Unit)>
@JvmField @Rule
val mockito = MockitoJUnit.rule()
+
+ private val mediaHeaderView: MediaHeaderView = MediaHeaderView(context, null)
private lateinit var keyguardMediaController: KeyguardMediaController
@Before
fun setup() {
+ // default state is positive, media should show up
+ whenever(mediaHost.visible).thenReturn(true)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
+ .thenReturn(true)
+ whenever(mediaHost.hostView).thenReturn(UniqueObjectHostView(context))
+
keyguardMediaController = KeyguardMediaController(mediaHost, bypassController,
statusBarStateController, notificationLockscreenUserManager)
+ keyguardMediaController.attachSinglePaneContainer(mediaHeaderView)
}
@Test
- fun testAttach_hiddenWhenHostIsHidden() {
- `when`(mediaHost.visible).thenReturn(false)
- triggerVisibilityListener()
+ fun testHiddenWhenHostIsHidden() {
+ whenever(mediaHost.visible).thenReturn(false)
- verify(mediaHeaderView, atLeastOnce()).visibility = eq(GONE)
- }
- @Test
- fun testAttach_visibleOnKeyguard() {
- `when`(mediaHost.visible).thenReturn(true)
- `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
- `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
- .thenReturn(true)
- triggerVisibilityListener()
+ keyguardMediaController.refreshMediaPosition()
- verify(mediaHeaderView, atLeastOnce()).visibility = eq(VISIBLE)
+ assertThat(mediaHeaderView.visibility).isEqualTo(GONE)
}
+
@Test
- fun testAttach_hiddenOnKeyguard_whenNotificationsAreHidden() {
- `when`(mediaHost.visible).thenReturn(true)
- `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
- `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
+ fun testVisibleOnKeyguardOrFullScreenUserSwitcher() {
+ testStateVisibility(StatusBarState.SHADE, GONE)
+ testStateVisibility(StatusBarState.SHADE_LOCKED, GONE)
+ testStateVisibility(StatusBarState.FULLSCREEN_USER_SWITCHER, VISIBLE)
+ testStateVisibility(StatusBarState.KEYGUARD, VISIBLE)
+ }
+
+ private fun testStateVisibility(state: Int, visibility: Int) {
+ whenever(statusBarStateController.state).thenReturn(state)
+ keyguardMediaController.refreshMediaPosition()
+ assertThat(mediaHeaderView.visibility).isEqualTo(visibility)
+ }
+
+ @Test
+ fun testHiddenOnKeyguard_whenNotificationsAreHidden() {
+ whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
.thenReturn(false)
- triggerVisibilityListener()
- verify(mediaHeaderView, atLeastOnce()).visibility = eq(GONE)
+ keyguardMediaController.refreshMediaPosition()
+
+ assertThat(mediaHeaderView.visibility).isEqualTo(GONE)
}
- private fun triggerVisibilityListener() {
- keyguardMediaController.attach(mediaHeaderView)
- verify(mediaHost).addVisibilityChangeListener(capture(visibilityListener))
- visibilityListener.value.invoke(true)
+ @Test
+ fun testActivatesSplitShadeContainerInSplitShadeMode() {
+ val splitShadeContainer = FrameLayout(context)
+ keyguardMediaController.attachSplitShadeContainer(
+ splitShadeContainer,
+ useContainer = { true })
+
+ keyguardMediaController.refreshMediaPosition()
+
+ assertThat(splitShadeContainer.visibility).isEqualTo(VISIBLE)
}
-}
\ No newline at end of file
+
+ @Test
+ fun testActivatesSinglePaneContainerInSinglePaneMode() {
+ val splitShadeContainer = FrameLayout(context)
+ keyguardMediaController.attachSplitShadeContainer(
+ splitShadeContainer,
+ useContainer = { false })
+
+ keyguardMediaController.refreshMediaPosition()
+
+ assertThat(splitShadeContainer.visibility).isEqualTo(GONE)
+ assertThat(mediaHeaderView.visibility).isEqualTo(VISIBLE)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
index 609b847..4a487be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
@@ -74,7 +74,7 @@
mMediaData = new MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null,
new ArrayList<>(), new ArrayList<>(), PACKAGE, null, null, null, true, null, true,
- false, KEY, false, false, false);
+ false, KEY, false, false, false, 0L);
mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
index 36b6527..a9d256b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.media
+import android.app.smartspace.SmartspaceTarget
import android.graphics.Color
import androidx.test.filters.SmallTest
import android.testing.AndroidTestingRunner
@@ -47,6 +48,7 @@
private const val ARTIST = "ARTIST"
private const val TITLE = "TITLE"
private const val DEVICE_NAME = "DEVICE_NAME"
+private const val SMARTSPACE_KEY = "SMARTSPACE_KEY"
private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
private fun <T> any(): T = Mockito.any()
@@ -68,6 +70,8 @@
private lateinit var lockscreenUserManager: NotificationLockscreenUserManager
@Mock
private lateinit var executor: Executor
+ @Mock
+ private lateinit var smartspaceData: SmartspaceTarget
private lateinit var mediaDataFilter: MediaDataFilter
private lateinit var dataMain: MediaData
@@ -91,6 +95,8 @@
dataGuest = MediaData(USER_GUEST, true, BG_COLOR, APP, null, ARTIST, TITLE, null,
emptyList(), emptyList(), PACKAGE, null, null, device, true, null)
+
+ `when`(smartspaceData.smartspaceTargetId).thenReturn(SMARTSPACE_KEY)
}
private fun setUser(id: Int) {
@@ -212,6 +218,61 @@
mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain)
mediaDataFilter.onSwipeToDismiss()
- verify(mediaDataManager).setTimedOut(eq(KEY), eq(true))
+ verify(mediaDataManager).setTimedOut(eq(KEY), eq(true), eq(true))
+ }
+
+ @Test
+ fun testOnSmartspaceMediaDataLoaded_noMedia_usesSmartspace() {
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ verify(listener).onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData))
+ assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
+ }
+
+ @Test
+ fun testOnSmartspaceMediaDataLoaded_noRecentMedia_usesSmartspace() {
+ val dataOld = dataMain.copy(active = false, lastActive = 0L)
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld)
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ verify(listener).onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData))
+ assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
+ }
+
+ @Test
+ fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_usesMedia() {
+ // WHEN we have media that was recently played, but not currently active
+ val dataCurrent = dataMain.copy(active = false, lastActive = System.currentTimeMillis())
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent))
+
+ // AND we get a smartspace signal
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ // THEN we should tell listeners to treat the media as active instead
+ val dataCurrentAndActive = dataCurrent.copy(active = true)
+ verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive))
+ assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
+ }
+
+ @Test
+ fun testOnSmartspaceMediaDataRemoved_usedSmartspace_clearsMedia() {
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+ mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
+
+ verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
+ assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
+ }
+
+ @Test
+ fun testOnSmartspaceMediaDataRemoved_usedMedia_clearsMedia() {
+ val dataCurrent = dataMain.copy(active = false, lastActive = System.currentTimeMillis())
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
+
+ verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrent))
+ assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 96eb4b0..678f89a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -60,6 +60,7 @@
@JvmField @Rule val mockito = MockitoJUnit.rule()
@Mock lateinit var mediaControllerFactory: MediaControllerFactory
@Mock lateinit var controller: MediaController
+ @Mock lateinit var playbackInfo: MediaController.PlaybackInfo
lateinit var session: MediaSession
lateinit var metadataBuilder: MediaMetadata.Builder
lateinit var backgroundExecutor: FakeExecutor
@@ -118,6 +119,9 @@
putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
}
whenever(mediaControllerFactory.create(eq(session.sessionToken))).thenReturn(controller)
+ whenever(controller.playbackInfo).thenReturn(playbackInfo)
+ whenever(playbackInfo.playbackType).thenReturn(
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL)
// This is an ugly hack for now. The mediaSessionBasedFilter is one of the internal
// listeners in the internal processing pipeline. It receives events, but ince it is a
@@ -230,6 +234,27 @@
}
@Test
+ fun testOnNotificationRemoved_withResumption_butNotLocal() {
+ // GIVEN that the manager has a notification with a resume action, but is not local
+ whenever(controller.metadata).thenReturn(metadataBuilder.build())
+ whenever(playbackInfo.playbackType).thenReturn(
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE)
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor))
+ val data = mediaDataCaptor.value
+ val dataRemoteWithResume = data.copy(resumeAction = Runnable {}, isLocalSession = false)
+ mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume)
+
+ // WHEN the notification is removed
+ mediaDataManager.onNotificationRemoved(KEY)
+
+ // THEN the media data is removed
+ verify(listener).onMediaDataRemoved(eq(KEY))
+ }
+
+ @Test
fun testAppBlockedFromResumption() {
// GIVEN that the manager has a notification with a resume action
whenever(controller.metadata).thenReturn(metadataBuilder.build())
@@ -280,11 +305,12 @@
@Test
fun testAddResumptionControls() {
- // WHEN resumption controls are added`
+ // WHEN resumption controls are added
val desc = MediaDescription.Builder().run {
setTitle(SESSION_TITLE)
build()
}
+ val currentTimeMillis = System.currentTimeMillis()
mediaDataManager.addResumptionControls(USER_ID, desc, Runnable {}, session.sessionToken,
APP_NAME, pendingIntent, PACKAGE_NAME)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
@@ -296,6 +322,7 @@
assertThat(data.song).isEqualTo(SESSION_TITLE)
assertThat(data.app).isEqualTo(APP_NAME)
assertThat(data.actions).hasSize(1)
+ assertThat(data.lastActive).isAtLeast(currentTimeMillis)
}
@Test
@@ -350,4 +377,52 @@
smartspaceMediaDataProvider.onTargetsAvailable(listOf())
verify(listener).onSmartspaceMediaDataRemoved(KEY_MEDIA_SMARTSPACE)
}
+
+ @Test
+ fun testOnMediaDataChanged_updatesLastActiveTime() {
+ val currentTimeMillis = System.currentTimeMillis()
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor))
+ assertThat(mediaDataCaptor.value!!.lastActive).isAtLeast(currentTimeMillis)
+ }
+
+ @Test
+ fun testOnMediaDataTimedOut_doesNotUpdateLastActiveTime() {
+ // GIVEN that the manager has a notification
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+
+ // WHEN the notification times out
+ val currentTimeMillis = System.currentTimeMillis()
+ mediaDataManager.setTimedOut(KEY, true, true)
+
+ // THEN the last active time is not changed
+ verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), capture(mediaDataCaptor))
+ assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTimeMillis)
+ }
+
+ @Test
+ fun testOnActiveMediaConverted_doesNotUpdateLastActiveTime() {
+ // GIVEN that the manager has a notification with a resume action
+ whenever(controller.metadata).thenReturn(metadataBuilder.build())
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor))
+ val data = mediaDataCaptor.value
+ assertThat(data.resumption).isFalse()
+ mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
+
+ // WHEN the notification is removed
+ val currentTimeMillis = System.currentTimeMillis()
+ mediaDataManager.onNotificationRemoved(KEY)
+
+ // THEN the last active time is not changed
+ verify(listener).onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor))
+ assertThat(mediaDataCaptor.value.resumption).isTrue()
+ assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTimeMillis)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
index 59c2b17..96d1d94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
@@ -182,6 +182,16 @@
}
@Test
+ fun testOnLoad_remotePlayback_doesNotCheck() {
+ // When media data is loaded that has not been checked yet, and is not local
+ val dataRemote = data.copy(isLocalSession = false)
+ resumeListener.onMediaDataLoaded(KEY, null, dataRemote)
+
+ // Then we do not take action
+ verify(mediaDataManager, never()).setResumeAction(any(), any())
+ }
+
+ @Test
fun testOnLoad_checksForResume_hasService() {
// Set up mocks to successfully find a MBS that returns valid media
val pm = mock(PackageManager::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
index f397959..0a573cd6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
@@ -227,4 +227,41 @@
mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
assertThat(mediaTimeoutListener.isTimedOut(KEY)).isFalse()
}
+
+ @Test
+ fun testOnSessionDestroyed_clearsTimeout() {
+ // GIVEN media that is paused
+ val mediaPaused = mediaData.copy(isPlaying = false)
+ mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaPaused)
+ verify(mediaController).registerCallback(capture(mediaCallbackCaptor))
+ assertThat(executor.numPending()).isEqualTo(1)
+
+ // WHEN the session is destroyed
+ mediaCallbackCaptor.value.onSessionDestroyed()
+
+ // THEN the controller is unregistered and timeout run
+ verify(mediaController).unregisterCallback(anyObject())
+ assertThat(executor.numPending()).isEqualTo(0)
+ }
+
+ @Test
+ fun testSessionDestroyed_thenRestarts_resetsTimeout() {
+ // Assuming we have previously destroyed the session
+ testOnSessionDestroyed_clearsTimeout()
+
+ // WHEN we get an update with media playing
+ val playingState = mock(android.media.session.PlaybackState::class.java)
+ `when`(playingState.state).thenReturn(PlaybackState.STATE_PLAYING)
+ `when`(mediaController.playbackState).thenReturn(playingState)
+ val mediaPlaying = mediaData.copy(isPlaying = true)
+ mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaPlaying)
+
+ // THEN the timeout runnable will update the state
+ assertThat(executor.numPending()).isEqualTo(1)
+ with(executor) {
+ advanceClockToNext()
+ runAllReady()
+ }
+ verify(timeoutCallback).invoke(eq(KEY), eq(false))
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/NotificationHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/NotificationHelperTest.java
index 7cddc3f..1b713dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/NotificationHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/NotificationHelperTest.java
@@ -19,6 +19,7 @@
import static com.android.systemui.people.NotificationHelper.getHighestPriorityNotification;
import static com.android.systemui.people.NotificationHelper.getMessagingStyleMessages;
+import static com.android.systemui.people.NotificationHelper.getSenderIfGroupConversation;
import static com.android.systemui.people.NotificationHelper.isMissedCall;
import static com.android.systemui.people.NotificationHelper.isMissedCallOrHasContent;
import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME;
@@ -32,6 +33,7 @@
import android.app.Person;
import android.content.pm.ShortcutInfo;
import android.net.Uri;
+import android.os.Bundle;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
@@ -202,4 +204,53 @@
assertThat(getHighestPriorityNotification(notifications))
.isEqualTo(mNotificationEntry1);
}
+
+ @Test
+ public void testGetSenderIfGroupConversation_notGroup() {
+ Notification.MessagingStyle.Message message = new Notification.MessagingStyle.Message(
+ NOTIFICATION_TEXT_3, 10, PERSON);
+ Notification notification = new Notification.Builder(mContext, "test")
+ .setContentTitle("TEST_TITLE")
+ .setContentText("TEST_TEXT")
+ .setShortcutId(SHORTCUT_ID_1)
+ .setStyle(new Notification.MessagingStyle(PERSON).addMessage(message))
+ .build();
+ assertThat(getSenderIfGroupConversation(notification, message)).isNull();
+ }
+
+ @Test
+ public void testGetSenderIfGroupConversation_group() {
+ Bundle extras = new Bundle();
+ extras.putBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION, true);
+ Notification.MessagingStyle.Message message = new Notification.MessagingStyle.Message(
+ NOTIFICATION_TEXT_3, 10, PERSON);
+
+ Notification notification = new Notification.Builder(mContext, "test")
+ .setContentTitle("TEST_TITLE")
+ .setContentText("TEST_TEXT")
+ .setShortcutId(SHORTCUT_ID_1)
+ .setStyle(new Notification.MessagingStyle(PERSON)
+ .setGroupConversation(true)
+ .addMessage(message))
+ .addExtras(extras)
+ .build();
+ assertThat(getSenderIfGroupConversation(notification, message)).isEqualTo("name");
+ }
+
+ @Test
+ public void testGetSenderIfGroupConversation_groupNoName() {
+ Bundle extras = new Bundle();
+ extras.putBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION, true);
+ Notification.MessagingStyle.Message message = new Notification.MessagingStyle.Message(
+ NOTIFICATION_TEXT_3, 10, new Person.Builder().build());
+
+ Notification notification = new Notification.Builder(mContext, "test")
+ .setContentTitle("TEST_TITLE")
+ .setContentText("TEST_TEXT")
+ .setShortcutId(SHORTCUT_ID_1)
+ .setStyle(new Notification.MessagingStyle(PERSON).addMessage(message))
+ .setExtras(extras)
+ .build();
+ assertThat(getSenderIfGroupConversation(notification, message)).isNull();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
index c929073..cc322620 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
@@ -59,6 +59,7 @@
import com.android.internal.appwidget.IAppWidgetService;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.people.widget.PeopleTileKey;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -94,6 +95,7 @@
private static final Uri URI = Uri.parse("fake_uri");
private static final Icon ICON = Icon.createWithResource("package", R.drawable.ic_android);
private static final String NAME = "username";
+ private static final UserHandle USER = new UserHandle(0);
private static final Person PERSON = new Person.Builder()
.setName("name")
.setKey("abc")
@@ -103,6 +105,7 @@
private static final PeopleSpaceTile PERSON_TILE =
new PeopleSpaceTile
.Builder(SHORTCUT_ID_1, NAME, ICON, new Intent())
+ .setUserHandle(USER)
.setLastInteractionTimestamp(123L)
.setNotificationKey(NOTIFICATION_KEY)
.setNotificationContent(NOTIFICATION_CONTENT)
@@ -231,10 +234,51 @@
.setPackageName(PACKAGE_NAME)
.setUserHandle(new UserHandle(0))
.build();
+ PeopleTileKey key = new PeopleTileKey(tile);
PeopleSpaceTile actual = PeopleSpaceUtils
- .augmentTileFromNotification(mContext, tile, mNotificationEntry1, 0);
+ .augmentTileFromNotification(mContext, tile, key, mNotificationEntry1, 0);
assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_TEXT_2);
+ assertThat(actual.getNotificationSender()).isEqualTo(null);
+ }
+
+ @Test
+ public void testAugmentTileFromNotificationGroupWithSender() {
+ Bundle extras = new Bundle();
+ extras.putBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION, true);
+ Notification notification = new Notification.Builder(mContext, "test")
+ .setContentTitle("TEST_TITLE")
+ .setContentText("TEST_TEXT")
+ .setShortcutId(SHORTCUT_ID_1)
+ .setStyle(new Notification.MessagingStyle(PERSON)
+ .setGroupConversation(true)
+ .addMessage(new Notification.MessagingStyle.Message(
+ NOTIFICATION_TEXT_1, 0, PERSON))
+ .addMessage(new Notification.MessagingStyle.Message(
+ NOTIFICATION_TEXT_2, 20, PERSON))
+ .addMessage(new Notification.MessagingStyle.Message(
+ NOTIFICATION_TEXT_3, 10, PERSON))
+ )
+ .setExtras(extras)
+ .build();
+ NotificationEntry notificationEntry = new NotificationEntryBuilder()
+ .setNotification(notification)
+ .setShortcutInfo(new ShortcutInfo.Builder(mContext, SHORTCUT_ID_1).build())
+ .setUser(UserHandle.of(0))
+ .setPkg(PACKAGE_NAME)
+ .build();
+ PeopleSpaceTile tile =
+ new PeopleSpaceTile
+ .Builder(SHORTCUT_ID_1, "userName", ICON, new Intent())
+ .setPackageName(PACKAGE_NAME)
+ .setUserHandle(new UserHandle(0))
+ .build();
+ PeopleTileKey key = new PeopleTileKey(tile);
+ PeopleSpaceTile actual = PeopleSpaceUtils
+ .augmentTileFromNotification(mContext, tile, key, notificationEntry, 0);
+
+ assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_TEXT_2);
+ assertThat(actual.getNotificationSender().toString()).isEqualTo("name");
}
@Test
@@ -245,8 +289,9 @@
.setPackageName(PACKAGE_NAME)
.setUserHandle(new UserHandle(0))
.build();
+ PeopleTileKey key = new PeopleTileKey(tile);
PeopleSpaceTile actual = PeopleSpaceUtils
- .augmentTileFromNotification(mContext, tile, mNotificationEntry3, 0);
+ .augmentTileFromNotification(mContext, tile, key, mNotificationEntry3, 0);
assertThat(actual.getNotificationContent()).isEqualTo(null);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
index 3cc55f2..d353d52 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
@@ -42,6 +42,7 @@
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
+import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
import android.util.DisplayMetrics;
import android.view.View;
@@ -73,10 +74,13 @@
private static final String GAME_DESCRIPTION = "Playing a game!";
private static final CharSequence MISSED_CALL = "Custom missed call message";
private static final String NAME = "username";
+ private static final UserHandle USER = new UserHandle(0);
+ private static final String SENDER = "sender";
private static final PeopleSpaceTile PERSON_TILE_WITHOUT_NOTIFICATION =
new PeopleSpaceTile
.Builder(SHORTCUT_ID_1, NAME, ICON, new Intent())
.setLastInteractionTimestamp(0L)
+ .setUserHandle(USER)
.build();
private static final PeopleSpaceTile PERSON_TILE =
new PeopleSpaceTile
@@ -85,6 +89,16 @@
.setNotificationKey(NOTIFICATION_KEY)
.setNotificationContent(NOTIFICATION_CONTENT)
.setNotificationDataUri(URI)
+ .setUserHandle(USER)
+ .build();
+ private static final PeopleSpaceTile PERSON_TILE_WITH_SENDER =
+ new PeopleSpaceTile
+ .Builder(SHORTCUT_ID_1, NAME, ICON, new Intent())
+ .setLastInteractionTimestamp(123L)
+ .setNotificationKey(NOTIFICATION_KEY)
+ .setNotificationContent(NOTIFICATION_CONTENT)
+ .setNotificationSender(SENDER)
+ .setUserHandle(USER)
.build();
private static final ConversationStatus GAME_STATUS =
new ConversationStatus
@@ -534,6 +548,86 @@
}
@Test
+ public void testCreateRemoteViewsWithNotificationWithSenderTemplate() {
+ PeopleSpaceTile tileWithStatusAndNotification = PERSON_TILE_WITH_SENDER.toBuilder()
+ .setNotificationDataUri(null)
+ .setStatuses(Arrays.asList(GAME_STATUS,
+ NEW_STORY_WITH_AVAILABILITY)).build();
+ RemoteViews views = new PeopleTileViewHelper(mContext,
+ tileWithStatusAndNotification, 0, mOptions).getViews();
+ View result = views.apply(mContext, null);
+
+ TextView name = (TextView) result.findViewById(R.id.name);
+ assertEquals(name.getText(), NAME);
+ TextView subtext = (TextView) result.findViewById(R.id.subtext);
+ assertEquals(View.VISIBLE, result.findViewById(R.id.subtext).getVisibility());
+ assertEquals(subtext.getText(), SENDER);
+ assertEquals(View.GONE, result.findViewById(R.id.predefined_icon).getVisibility());
+ // Has availability.
+ assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
+ // Has person icon.
+ assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
+ // Has notification content.
+ TextView statusContent = (TextView) result.findViewById(R.id.text_content);
+ assertEquals(View.VISIBLE, statusContent.getVisibility());
+ assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
+
+ // Subtract one from lines because sender is included.
+ assertThat(statusContent.getMaxLines()).isEqualTo(2);
+
+ // Has a single message, no count shown.
+ assertEquals(View.GONE, result.findViewById(R.id.messages_count).getVisibility());
+
+ mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
+ getSizeInDp(R.dimen.required_width_for_medium) - 1);
+ RemoteViews smallView = new PeopleTileViewHelper(mContext,
+ tileWithStatusAndNotification, 0, mOptions).getViews();
+ View smallResult = smallView.apply(mContext, null);
+
+ // Show icon instead of name.
+ assertEquals(View.GONE, smallResult.findViewById(R.id.name).getVisibility());
+ assertEquals(View.VISIBLE,
+ smallResult.findViewById(R.id.predefined_icon).getVisibility());
+ // Has person icon.
+ assertEquals(View.VISIBLE,
+ smallResult.findViewById(R.id.person_icon).getVisibility());
+
+ // Has a single message, no count shown.
+ assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());
+
+ mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
+ getSizeInDp(R.dimen.required_width_for_large));
+ mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
+ getSizeInDp(R.dimen.required_height_for_large));
+ RemoteViews largeView = new PeopleTileViewHelper(mContext,
+ tileWithStatusAndNotification, 0, mOptions).getViews();
+ View largeResult = largeView.apply(mContext, null);
+
+ name = (TextView) largeResult.findViewById(R.id.name);
+ assertEquals(name.getText(), NAME);
+ subtext = (TextView) largeResult.findViewById(R.id.subtext);
+ assertEquals(View.VISIBLE, largeResult.findViewById(R.id.subtext).getVisibility());
+ assertEquals(subtext.getText(), SENDER);
+ assertEquals(View.GONE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
+ // Has availability.
+ assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
+ // Has person icon.
+ View personIcon = largeResult.findViewById(R.id.person_icon);
+ assertEquals(View.VISIBLE, personIcon.getVisibility());
+ // Has notification content.
+ statusContent = (TextView) largeResult.findViewById(R.id.text_content);
+ assertEquals(View.VISIBLE, statusContent.getVisibility());
+ assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
+
+ // Subtract one from lines because sender is included.
+ assertThat(statusContent.getMaxLines()).isEqualTo(2);
+
+ // Has a single message, no count shown.
+ assertEquals(View.GONE, largeResult.findViewById(R.id.messages_count).getVisibility());
+
+ }
+
+ @Test
public void testCreateRemoteViewsWithNotificationTemplateTwoMessages() {
PeopleSpaceTile tileWithStatusAndNotification = PERSON_TILE.toBuilder()
.setNotificationDataUri(null)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index 725e5d4..411fb02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -1201,7 +1201,8 @@
.setPackageName(TEST_PACKAGE_A)
.setUserHandle(new UserHandle(0))
.build();
- PeopleSpaceTile actual = mManager.augmentTileFromNotifications(tile, EMPTY_STRING,
+ PeopleTileKey key = new PeopleTileKey(tile);
+ PeopleSpaceTile actual = mManager.augmentTileFromNotifications(tile, key, EMPTY_STRING,
Map.of(new PeopleTileKey(mNotificationEntry),
new HashSet<>(Collections.singleton(mNotificationEntry))));
@@ -1216,8 +1217,9 @@
.setPackageName(TEST_PACKAGE_A)
.setUserHandle(new UserHandle(0))
.build();
+ PeopleTileKey key = new PeopleTileKey(tile);
PeopleSpaceTile actual = mManager
- .augmentTileFromNotifications(tile, EMPTY_STRING,
+ .augmentTileFromNotifications(tile, key, EMPTY_STRING,
Map.of(new PeopleTileKey(mNotificationEntry),
new HashSet<>(Collections.singleton(mNotificationEntry))));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
index 05a1e4f..03248f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
@@ -179,6 +179,9 @@
@Test
fun testShowDialogShowsDialog() {
+ val usage = createMockPermGroupUsage()
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
+
controller.showDialog(context)
exhaustExecutors()
@@ -186,7 +189,17 @@
}
@Test
+ fun testDontShowEmptyDialog() {
+ controller.showDialog(context)
+ exhaustExecutors()
+
+ verify(dialog, never()).show()
+ }
+
+ @Test
fun testHideDialogDismissesDialogIfShown() {
+ val usage = createMockPermGroupUsage()
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context)
exhaustExecutors()
@@ -202,6 +215,8 @@
@Test
fun testHideDialogNoopAfterDismissed() {
+ val usage = createMockPermGroupUsage()
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context)
exhaustExecutors()
@@ -214,6 +229,8 @@
@Test
fun testShowForAllUsers() {
+ val usage = createMockPermGroupUsage()
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context)
exhaustExecutors()
@@ -439,7 +456,7 @@
controller.showDialog(context)
exhaustExecutors()
- assertThat(dialogProvider.list).isEmpty()
+ verify(dialog, never()).show()
}
@Test
@@ -467,11 +484,13 @@
controller.showDialog(context)
exhaustExecutors()
- assertThat(dialogProvider.list).isEmpty()
+ verify(dialog, never()).show()
}
@Test
fun testStartActivityCorrectIntent() {
+ val usage = createMockPermGroupUsage()
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context)
exhaustExecutors()
@@ -488,6 +507,8 @@
@Test
fun testStartActivityCorrectIntent_enterpriseUser() {
+ val usage = createMockPermGroupUsage()
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context)
exhaustExecutors()
@@ -501,6 +522,8 @@
@Test
fun testStartActivitySuccess() {
+ val usage = createMockPermGroupUsage()
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context)
exhaustExecutors()
@@ -514,6 +537,8 @@
@Test
fun testStartActivityFailure() {
+ val usage = createMockPermGroupUsage()
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
controller.showDialog(context)
exhaustExecutors()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
index 21fec91..d35597f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -42,7 +42,7 @@
import com.android.systemui.globalactions.GlobalActionsDialogLite;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.phone.MultiUserSwitch;
+import com.android.systemui.statusbar.phone.MultiUserSwitchController;
import com.android.systemui.statusbar.phone.SettingsButton;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.UserInfoController;
@@ -90,7 +90,7 @@
@Mock
private View mEdit;
@Mock
- private MultiUserSwitch mMultiUserSwitch;
+ private MultiUserSwitchController mMultiUserSwitchController;
@Mock
private View mPowerMenuLiteView;
@Mock
@@ -116,12 +116,11 @@
when(mView.findViewById(R.id.settings_button)).thenReturn(mSettingsButton);
when(mView.findViewById(R.id.build)).thenReturn(mBuildText);
when(mView.findViewById(android.R.id.edit)).thenReturn(mEdit);
- when(mView.findViewById(R.id.multi_user_switch)).thenReturn(mMultiUserSwitch);
when(mView.findViewById(R.id.pm_lite)).thenReturn(mPowerMenuLiteView);
mController = new QSFooterViewController(mView, mUserManager, mUserInfoController,
mActivityStarter, mDeviceProvisionedController, mUserTracker, mQSPanelController,
- new QSDetailDisplayer(), mQuickQSPanelController, mFakeTunerService,
+ mMultiUserSwitchController, mQuickQSPanelController, mFakeTunerService,
mMetricsLogger, new FalsingManagerFake(), false, mGlobalActionsDialog);
mController.init();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index 4ee639b..234dec2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -81,10 +81,10 @@
private static final String PARENTAL_CONTROLS_LABEL = "Parental Control App";
private static final ComponentName DEVICE_OWNER_COMPONENT =
new ComponentName("TestDPC", "Test");
+ private static final int DEFAULT_ICON_ID = R.drawable.ic_info_outline;
private ViewGroup mRootView;
private TextView mFooterText;
- private TestableImageView mFooterIcon;
private TestableImageView mPrimaryFooterIcon;
private QSSecurityFooter mFooter;
@Mock
@@ -101,11 +101,10 @@
when(mUserTracker.getUserInfo()).thenReturn(mock(UserInfo.class));
mRootView = (ViewGroup) new LayoutInflaterBuilder(mContext)
.replace("ImageView", TestableImageView.class)
- .build().inflate(R.layout.quick_settings_footer, null, false);
+ .build().inflate(R.layout.quick_settings_security_footer, null, false);
mFooter = new QSSecurityFooter(mRootView, mUserTracker, new Handler(looper),
mActivityStarter, mSecurityController, looper);
mFooterText = mRootView.findViewById(R.id.footer_text);
- mFooterIcon = mRootView.findViewById(R.id.footer_icon);
mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon);
mFooter.setHostEnvironment(null);
@@ -135,10 +134,8 @@
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management),
mFooterText.getText());
assertEquals(View.VISIBLE, mRootView.getVisibility());
- assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
- assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
- // -1 == never set.
- assertEquals(-1, mFooterIcon.getLastImageResource());
+ assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
+ assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
}
@Test
@@ -153,10 +150,8 @@
MANAGING_ORGANIZATION),
mFooterText.getText());
assertEquals(View.VISIBLE, mRootView.getVisibility());
- assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
- assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
- // -1 == never set.
- assertEquals(-1, mFooterIcon.getLastImageResource());
+ assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
+ assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
}
@Test
@@ -174,10 +169,8 @@
R.string.quick_settings_financed_disclosure_named_management,
MANAGING_ORGANIZATION), mFooterText.getText());
assertEquals(View.VISIBLE, mRootView.getVisibility());
- assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
- assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
- // -1 == never set.
- assertEquals(-1, mFooterIcon.getLastImageResource());
+ assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
+ assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
}
@Test
@@ -204,10 +197,8 @@
TestableLooper.get(this).processAllMessages();
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_monitoring),
mFooterText.getText());
- assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
- assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
- // -1 == never set.
- assertEquals(-1, mFooterIcon.getLastImageResource());
+ assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
+ assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
// Same situation, but with organization name set
when(mSecurityController.getDeviceOwnerOrganizationName())
@@ -255,9 +246,8 @@
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_named_vpn,
VPN_PACKAGE),
mFooterText.getText());
- assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
- assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
- assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
+ assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
+ assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource());
// Same situation, but with organization name set
when(mSecurityController.getDeviceOwnerOrganizationName())
@@ -282,9 +272,8 @@
TestableLooper.get(this).processAllMessages();
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_vpns),
mFooterText.getText());
- assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
- assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
- assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
+ assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
+ assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource());
// Same situation, but with organization name set
when(mSecurityController.getDeviceOwnerOrganizationName())
@@ -306,9 +295,8 @@
mFooter.refreshState();
TestableLooper.get(this).processAllMessages();
- assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
- assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
- assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
+ assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
+ assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource());
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_monitoring),
mFooterText.getText());
}
@@ -320,8 +308,7 @@
mFooter.refreshState();
TestableLooper.get(this).processAllMessages();
- // -1 == never set.
- assertEquals(-1, mFooterIcon.getLastImageResource());
+ assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
assertEquals(mContext.getString(
R.string.quick_settings_disclosure_managed_profile_monitoring),
mFooterText.getText());
@@ -345,8 +332,7 @@
mFooter.refreshState();
TestableLooper.get(this).processAllMessages();
- // -1 == never set.
- assertEquals(-1, mFooterIcon.getLastImageResource());
+ assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
assertEquals(mContext.getString(R.string.quick_settings_disclosure_monitoring),
mFooterText.getText());
}
@@ -359,7 +345,7 @@
mFooter.refreshState();
TestableLooper.get(this).processAllMessages();
- assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
+ assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource());
assertEquals(mContext.getString(R.string.quick_settings_disclosure_vpns),
mFooterText.getText());
}
@@ -371,7 +357,7 @@
mFooter.refreshState();
TestableLooper.get(this).processAllMessages();
- assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
+ assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource());
assertEquals(mContext.getString(
R.string.quick_settings_disclosure_managed_profile_named_vpn,
VPN_PACKAGE_2),
@@ -412,7 +398,7 @@
mFooter.refreshState();
TestableLooper.get(this).processAllMessages();
- assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
+ assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource());
assertEquals(mContext.getString(R.string.quick_settings_disclosure_named_vpn,
VPN_PACKAGE),
mFooterText.getText());
@@ -648,12 +634,12 @@
assertEquals(testDrawable, mPrimaryFooterIcon.getDrawable());
- // Ensure the primary icon is set to gone when parental controls is disabled.
+ // Ensure the primary icon is back to default after parental controls are gone
when(mSecurityController.isParentalControlsEnabled()).thenReturn(false);
mFooter.refreshState();
TestableLooper.get(this).processAllMessages();
- assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
+ assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
index 51aeb15..6cf3434 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
@@ -165,7 +165,12 @@
@Test
fun testLongClickIntent() {
- assertThat(tile.longClickIntent.action).isEqualTo(Settings.ACTION_DEVICE_CONTROLS_SETTINGS)
+ assertThat(tile.longClickIntent).isNull()
+ }
+
+ @Test
+ fun testDoesNotHandleLongClick() {
+ assertThat(tile.state.handlesLongClick).isFalse()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
index f48b3fc..af75f2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
@@ -28,6 +28,7 @@
import com.android.internal.util.UserIcons
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.qs.QSUserSwitcherEvent
import com.android.systemui.statusbar.policy.UserSwitcherController
import org.junit.Assert.assertEquals
@@ -53,6 +54,7 @@
@Mock private lateinit var mInflatedUserDetailItemView: UserDetailItemView
@Mock private lateinit var mUserInfo: UserInfo
@Mock private lateinit var mLayoutInflater: LayoutInflater
+ private var falsingManagerFake: FalsingManagerFake = FalsingManagerFake()
private lateinit var adapter: UserDetailView.Adapter
private lateinit var uiEventLogger: UiEventLoggerFake
private lateinit var mPicture: Bitmap
@@ -65,7 +67,8 @@
mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, mLayoutInflater)
`when`(mLayoutInflater.inflate(anyInt(), any(ViewGroup::class.java), anyBoolean()))
.thenReturn(mInflatedUserDetailItemView)
- adapter = UserDetailView.Adapter(mContext, mUserSwitcherController, uiEventLogger)
+ adapter = UserDetailView.Adapter(mContext, mUserSwitcherController, uiEventLogger,
+ falsingManagerFake)
mPicture = UserIcons.convertToBitmap(mContext.getDrawable(R.drawable.ic_avatar_user))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
index 8c7d762..3d658ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.screenshot;
+import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType.REGULAR_SMART_ACTIONS;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -87,6 +89,7 @@
CompletableFuture<List<Notification.Action>> smartActionsFuture =
mScreenshotSmartActions.getSmartActionsFuture(
"", Uri.parse("content://authority/data"), bitmap, smartActionsProvider,
+ REGULAR_SMART_ACTIONS,
true, UserHandle.of(UserHandle.myUserId()));
assertNotNull(smartActionsFuture);
List<Notification.Action> smartActions = smartActionsFuture.get(5, TimeUnit.MILLISECONDS);
@@ -104,7 +107,7 @@
when(smartActionsFuture.get(timeoutMs, TimeUnit.MILLISECONDS)).thenThrow(
RuntimeException.class);
List<Notification.Action> actions = mScreenshotSmartActions.getSmartActions(
- "", smartActionsFuture, timeoutMs, mSmartActionsProvider);
+ "", smartActionsFuture, timeoutMs, mSmartActionsProvider, REGULAR_SMART_ACTIONS);
assertEquals(Collections.emptyList(), actions);
}
@@ -127,6 +130,7 @@
CompletableFuture<List<Notification.Action>> smartActionsFuture =
mScreenshotSmartActions.getSmartActionsFuture(
"", Uri.parse("content://autority/data"), bitmap, mSmartActionsProvider,
+ REGULAR_SMART_ACTIONS,
true, UserHandle.of(UserHandle.myUserId()));
verify(mSmartActionsProvider, never()).getActions(any(), any(), any(), any(), any(), any());
assertNotNull(smartActionsFuture);
@@ -140,7 +144,8 @@
Bitmap bitmap = mock(Bitmap.class);
when(bitmap.getConfig()).thenReturn(Bitmap.Config.HARDWARE);
mScreenshotSmartActions.getSmartActionsFuture(
- "", Uri.parse("content://autority/data"), bitmap, mSmartActionsProvider, true,
+ "", Uri.parse("content://autority/data"), bitmap, mSmartActionsProvider,
+ REGULAR_SMART_ACTIONS, true,
UserHandle.of(UserHandle.myUserId()));
verify(mSmartActionsProvider, times(1)).getActions(
any(), any(), any(), any(), any(), any());
@@ -157,7 +162,7 @@
mContext, null, mHandler);
CompletableFuture<List<Notification.Action>> smartActionsFuture =
mScreenshotSmartActions.getSmartActionsFuture("", null, bitmap,
- actionsProvider,
+ actionsProvider, REGULAR_SMART_ACTIONS,
true, UserHandle.of(UserHandle.myUserId()));
assertNotNull(smartActionsFuture);
List<Notification.Action> smartActions = smartActionsFuture.get(5, TimeUnit.MILLISECONDS);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/scrim/ScrimViewTest.java
similarity index 94%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/scrim/ScrimViewTest.java
index c2e58ef..a345f78 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/scrim/ScrimViewTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,10 +11,10 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
-package com.android.systemui.statusbar;
+package com.android.systemui.scrim;
import static junit.framework.Assert.assertEquals;
@@ -31,7 +31,6 @@
import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.utils.leaks.LeakCheckedTest;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index 45a7d0a..a0c3ed9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -69,7 +69,6 @@
@Mock private lateinit var shadeSpring: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var shadeAnimation: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var globalActionsSpring: NotificationShadeDepthController.DepthAnimation
- @Mock private lateinit var brightnessSpring: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var listener: NotificationShadeDepthController.DepthListener
@Mock private lateinit var dozeParameters: DozeParameters
@JvmField @Rule val mockitoRule = MockitoJUnit.rule()
@@ -97,7 +96,6 @@
notificationShadeWindowController, dozeParameters, dumpManager)
notificationShadeDepthController.shadeSpring = shadeSpring
notificationShadeDepthController.shadeAnimation = shadeAnimation
- notificationShadeDepthController.brightnessMirrorSpring = brightnessSpring
notificationShadeDepthController.globalActionsSpring = globalActionsSpring
notificationShadeDepthController.root = root
@@ -245,31 +243,6 @@
}
@Test
- fun brightnessMirrorVisible_whenVisible() {
- notificationShadeDepthController.brightnessMirrorVisible = true
- verify(brightnessSpring).animateTo(eq(maxBlur), any())
- }
-
- @Test
- fun brightnessMirrorVisible_whenHidden() {
- notificationShadeDepthController.brightnessMirrorVisible = false
- verify(brightnessSpring).animateTo(eq(0), any())
- }
-
- @Test
- fun brightnessMirror_hidesShadeBlur() {
- // Brightness mirror is fully visible
- `when`(brightnessSpring.ratio).thenReturn(1f)
- // And shade is blurred
- `when`(shadeSpring.radius).thenReturn(maxBlur)
- `when`(shadeAnimation.radius).thenReturn(maxBlur)
-
- notificationShadeDepthController.updateBlurCallback.doFrame(0)
- verify(notificationShadeWindowController).setBackgroundBlurRadius(0)
- verify(blurUtils).applyBlur(eq(viewRootImpl), eq(0))
- }
-
- @Test
fun setNotificationLaunchAnimationParams_schedulesFrame() {
val animProgress = ExpandAnimationParameters()
animProgress.linearProgress = 0.5f
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index c832fe4..bdd4a01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -21,6 +21,8 @@
import android.app.NotificationManager.IMPORTANCE_DEFAULT
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.NotificationManager.IMPORTANCE_LOW
+import android.app.PendingIntent
+import android.app.Person
import android.os.SystemClock
import android.service.notification.NotificationListenerService.RankingMap
import android.testing.AndroidTestingRunner
@@ -408,6 +410,74 @@
assertThat(b.bucket).isEqualTo(BUCKET_FOREGROUND_SERVICE)
}
+ @Test
+ fun testSort_importantCall() {
+ whenever(sectionsManager.isFilteringEnabled()).thenReturn(true)
+
+ val a = NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_HIGH)
+ .setPkg("pkg")
+ .setOpPkg("pkg")
+ .setTag("tag")
+ .setNotification(
+ Notification.Builder(mContext, "test")
+ .build())
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
+ .setUser(mContext.getUser())
+ .setOverrideGroupKey("")
+ .build()
+
+ val b = NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_DEFAULT) // high priority
+ .setPkg("pkg2")
+ .setOpPkg("pkg2")
+ .setTag("tag")
+ .setNotification(mock(Notification::class.java).also { notif ->
+ whenever(notif.isForegroundService).thenReturn(true)
+ whenever(notif.isColorized).thenReturn(true)
+ })
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
+ .setUser(mContext.getUser())
+ .setOverrideGroupKey("")
+ .build()
+
+ val cN = Notification.Builder(mContext, "test")
+ .setStyle(Notification.MessagingStyle(""))
+ .build()
+ val c = NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_HIGH)
+ .setPkg("pkg")
+ .setOpPkg("pkg")
+ .setTag("tag")
+ .setNotification(cN)
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
+ .setUser(mContext.user)
+ .setOverrideGroupKey("")
+ .build()
+
+ val dN = Notification.Builder(mContext, "test")
+ .setStyle(Notification.CallStyle.forOngoingCall(
+ Person.Builder().setName("caller").build(),
+ mock(PendingIntent::class.java)))
+ .build()
+ val d = NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_DEFAULT) // high priority
+ .setPkg("pkg2")
+ .setOpPkg("pkg2")
+ .setTag("tag")
+ .setNotification(dN)
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
+ .setUser(mContext.user)
+ .setOverrideGroupKey("")
+ .build()
+ whenever(personNotificationIdentifier.getPeopleNotificationType(a))
+ .thenReturn(TYPE_IMPORTANT_PERSON)
+
+ assertThat(rankingManager.updateRanking(null, listOf(a, b, c, d), "test"))
+ .containsExactly(b, d, c, a)
+ assertThat(d.bucket).isEqualTo(BUCKET_FOREGROUND_SERVICE)
+ }
+
internal class TestableNotificationRankingManager(
mediaManager: Lazy<NotificationMediaManager>,
groupManager: NotificationGroupManagerLegacy,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index 4183508..94e273b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.notification.row;
-import static org.mockito.ArgumentMatchers.anyFloat;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -57,7 +55,6 @@
mView = new NotificationContentView(mContext, null);
ExpandableNotificationRow row = new ExpandableNotificationRow(mContext, null);
ExpandableNotificationRow mockRow = spy(row);
- doNothing().when(mockRow).updateBackgroundAlpha(anyFloat());
doReturn(10).when(mockRow).getIntrinsicHeight();
mView.setContainingNotification(mockRow);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index f1c8ece..a63d509 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -123,6 +123,7 @@
verify(mStatusBarKeyguardViewManager).showBouncer(eq(false));
verify(mShadeController).animateCollapsePanels(anyInt(), anyBoolean(), anyBoolean(),
anyFloat());
+ verify(mStatusBarKeyguardViewManager, never()).notifyKeyguardAuthenticated(anyBoolean());
assertThat(mBiometricUnlockController.getMode())
.isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER);
}
@@ -170,6 +171,7 @@
verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
verify(mShadeController).animateCollapsePanels(anyInt(), anyBoolean(), anyBoolean(),
anyFloat());
+ verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
assertThat(mBiometricUnlockController.getMode())
.isEqualTo(BiometricUnlockController.MODE_UNLOCK_COLLAPSING);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index 0e3e0cc..a01e0b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -31,6 +31,7 @@
import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
import android.view.ViewPropertyAnimator;
+import android.widget.FrameLayout;
import androidx.test.filters.SmallTest;
@@ -40,24 +41,19 @@
import com.android.systemui.statusbar.events.PrivacyDotViewController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
-import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
-import java.util.Objects;
-
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
- private NotificationIconAreaController mMockNotificiationAreaController;
+ private NotificationIconAreaController mMockNotificationAreaController;
private View mNotificationAreaInner;
- private View mCenteredNotificationAreaView;
private StatusBarStateController mStatusBarStateController;
private OngoingCallController mOngoingCallController;
private SystemStatusAnimationScheduler mAnimationScheduler;
@@ -74,26 +70,16 @@
mStatusBarStateController = mDependency
.injectMockDependency(StatusBarStateController.class);
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
- mMockNotificiationAreaController = mock(NotificationIconAreaController.class);
- mNotificationAreaInner = mock(View.class);
- mCenteredNotificationAreaView = mock(View.class);
when(statusBar.getPanelController()).thenReturn(
mock(NotificationPanelViewController.class));
- when(mNotificationAreaInner.animate()).thenReturn(mock(ViewPropertyAnimator.class));
- when(mMockNotificiationAreaController.getNotificationInnerAreaView()).thenReturn(
- mNotificationAreaInner);
- when(mCenteredNotificationAreaView.animate()).thenReturn(mock(ViewPropertyAnimator.class));
- when(mMockNotificiationAreaController.getCenteredNotificationAreaView()).thenReturn(
- mCenteredNotificationAreaView);
}
@Test
public void testDisableNone() throws Exception {
mFragments.dispatchResume();
processAllMessages();
-
CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
- fragment.initNotificationIconArea(mMockNotificiationAreaController);
+
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
@@ -106,9 +92,8 @@
public void testDisableSystemInfo() throws Exception {
mFragments.dispatchResume();
processAllMessages();
-
CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
- fragment.initNotificationIconArea(mMockNotificiationAreaController);
+
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
assertEquals(View.INVISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
@@ -124,12 +109,11 @@
public void testDisableNotifications() throws Exception {
mFragments.dispatchResume();
processAllMessages();
-
CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
- fragment.initNotificationIconArea(mMockNotificiationAreaController);
+
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
- Mockito.verify(mNotificationAreaInner).setVisibility(eq(View.INVISIBLE));
+ Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE));
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
@@ -140,9 +124,8 @@
public void testDisableClock() throws Exception {
mFragments.dispatchResume();
processAllMessages();
-
CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
- fragment.initNotificationIconArea(mMockNotificiationAreaController);
+
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_CLOCK, 0, false);
assertEquals(View.GONE, mFragment.getView().findViewById(R.id.clock).getVisibility());
@@ -153,15 +136,81 @@
}
@Test
+ public void disable_noOngoingCall_chipHidden() {
+ mFragments.dispatchResume();
+ processAllMessages();
+ CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+
+ when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
+
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ assertEquals(View.GONE,
+ mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ }
+
+ @Test
+ public void disable_hasOngoingCall_chipDisplayedAndNotificationIconsHidden() {
+ mFragments.dispatchResume();
+ processAllMessages();
+ CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+
+ when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
+
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ assertEquals(View.VISIBLE,
+ mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE));
+
+ }
+
+ @Test
+ public void disable_hasOngoingCallButNotificationIconsDisabled_chipHidden() {
+ mFragments.dispatchResume();
+ processAllMessages();
+ CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+
+ when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
+
+ fragment.disable(DEFAULT_DISPLAY,
+ StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
+
+ assertEquals(View.GONE,
+ mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ }
+
+ @Test
+ public void disable_ongoingCallEnded_chipHidden() {
+ mFragments.dispatchResume();
+ processAllMessages();
+ CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+
+ when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
+
+ // Ongoing call started
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+ assertEquals(View.VISIBLE,
+ mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+
+ // Ongoing call ended
+ when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
+
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ assertEquals(View.GONE,
+ mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+ }
+
+ @Test
public void testOnDozingChanged() throws Exception {
mFragments.dispatchResume();
processAllMessages();
-
CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
- fragment.initNotificationIconArea(mMockNotificiationAreaController);
+
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
- Mockito.verify(mNotificationAreaInner).setVisibility(eq(View.INVISIBLE));
+ Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE));
reset(mStatusBarStateController);
when(mStatusBarStateController.isDozing()).thenReturn(true);
@@ -171,56 +220,35 @@
Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE));
}
- @Test
- public void onOngoingCallStarted_notificationsHiddenAndOngoingCallChipDisplayed() {
- mFragments.dispatchResume();
- processAllMessages();
-
- CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
- fragment.initNotificationIconArea(mMockNotificiationAreaController);
-
- ArgumentCaptor<OngoingCallListener> ongoingCallListenerCaptor = ArgumentCaptor.forClass(
- OngoingCallListener.class);
- Mockito.verify(mOngoingCallController).addCallback(ongoingCallListenerCaptor.capture());
- OngoingCallListener listener = Objects.requireNonNull(ongoingCallListenerCaptor.getValue());
-
- when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
- listener.onOngoingCallStarted(/* animate= */ false);
-
- assertEquals(View.VISIBLE,
- mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
- Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE));
- }
-
- @Test
- public void onOngoingCallEnded_notificationsDisplayedAndOngoingCallChipHidden() {
- mFragments.dispatchResume();
- processAllMessages();
-
- CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
- fragment.initNotificationIconArea(mMockNotificiationAreaController);
-
- ArgumentCaptor<OngoingCallListener> ongoingCallListenerCaptor = ArgumentCaptor.forClass(
- OngoingCallListener.class);
- Mockito.verify(mOngoingCallController).addCallback(ongoingCallListenerCaptor.capture());
- OngoingCallListener listener = Objects.requireNonNull(ongoingCallListenerCaptor.getValue());
-
- when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
- listener.onOngoingCallEnded(/* animate= */ false);
-
- assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
- Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE));
- }
-
@Override
protected Fragment instantiate(Context context, String className, Bundle arguments) {
mOngoingCallController = mock(OngoingCallController.class);
mAnimationScheduler = mock(SystemStatusAnimationScheduler.class);
mDotViewController = mock(PrivacyDotViewController.class);
+ setUpNotificationIconAreaController();
return new CollapsedStatusBarFragment(
mOngoingCallController,
mAnimationScheduler,
- mDotViewController);
+ mDotViewController,
+ mMockNotificationAreaController);
+ }
+
+ private void setUpNotificationIconAreaController() {
+ mMockNotificationAreaController = mock(NotificationIconAreaController.class);
+
+ mNotificationAreaInner = mock(View.class);
+ View centeredNotificationAreaView = mock(View.class);
+
+ when(mNotificationAreaInner.getLayoutParams()).thenReturn(
+ new FrameLayout.LayoutParams(100, 100));
+ when(centeredNotificationAreaView.getLayoutParams()).thenReturn(
+ new FrameLayout.LayoutParams(100, 100));
+ when(mNotificationAreaInner.animate()).thenReturn(mock(ViewPropertyAnimator.class));
+ when(centeredNotificationAreaView.animate()).thenReturn(mock(ViewPropertyAnimator.class));
+
+ when(mMockNotificationAreaController.getCenteredNotificationAreaView()).thenReturn(
+ centeredNotificationAreaView);
+ when(mMockNotificationAreaController.getNotificationInnerAreaView()).thenReturn(
+ mNotificationAreaInner);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 02e2e4c..152ba90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -53,6 +53,7 @@
private boolean mHasVisibleNotifs;
private float mQsExpansion;
private int mCutoutTopInset = 0; // in pixels
+ private boolean mIsSplitShade = false;
@Before
public void setUp() {
@@ -265,6 +266,19 @@
}
@Test
+ public void notifPositionAlignedWithClockInSplitShadeMode() {
+ // GIVEN on lock screen and split shade mode
+ givenLockScreen();
+ mIsSplitShade = true;
+ mPreferredClockY = 100;
+ mHasCustomClock = true;
+ // WHEN the position algorithm is run
+ positionClock();
+ // THEN the notif padding DOESN'T adjust for keyguard status height.
+ assertThat(mClockPosition.stackScrollerPadding).isEqualTo(mPreferredClockY);
+ }
+
+ @Test
public void notifPositionWithLargeClockOnLockScreen() {
// GIVEN on lock screen and clock has a nonzero height
givenLockScreen();
@@ -397,7 +411,7 @@
0 /* userSwitchHeight */, mPreferredClockY, 0 /* userSwitchPreferredY */,
mHasCustomClock, mHasVisibleNotifs, mDark, ZERO_DRAG, false /* bypassEnabled */,
0 /* unlockedStackScrollerPadding */, mQsExpansion,
- mCutoutTopInset);
+ mCutoutTopInset, mIsSplitShade);
mClockPositionAlgorithm.run(mClockPosition);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index cebf8be..4bac762 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -75,6 +75,7 @@
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.doze.DozeLog;
+import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.qs.QSDetailDisplayer;
@@ -240,6 +241,8 @@
private LockIconViewController mLockIconViewController;
@Mock
private QuickAccessWalletClient mQuickAccessWalletClient;
+ @Mock
+ private KeyguardMediaController mKeyguardMediaController;
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -282,6 +285,7 @@
mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame));
mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller));
+ mNotificationContainerParent.addView(newViewWithId(R.id.keyguard_status_view));
when(mView.findViewById(R.id.notification_container_parent))
.thenReturn(mNotificationContainerParent);
FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(
@@ -346,6 +350,7 @@
mLockIconViewController,
mFeatureFlags,
mQuickAccessWalletClient,
+ mKeyguardMediaController,
new FakeExecutor(new FakeSystemClock()));
mNotificationPanelViewController.initDependencies(
mStatusBar,
@@ -476,6 +481,20 @@
}
@Test
+ public void testKeyguardStatusView_isAlignedToGuidelineInSplitShadeMode() {
+ mNotificationPanelViewController.updateResources();
+
+ assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd)
+ .isEqualTo(ConstraintSet.PARENT_ID);
+
+ enableSplitShade();
+ mNotificationPanelViewController.updateResources();
+
+ assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd)
+ .isEqualTo(R.id.qs_edge_guideline);
+ }
+
+ @Test
public void testSplitShadeLayout_isAlignedToGuideline() {
enableSplitShade();
@@ -553,6 +572,36 @@
assertThat(mNotificationPanelViewController.canCollapsePanelOnTouch()).isFalse();
}
+ @Test
+ public void testSwipeWhileLocked_notifiesKeyguardState() {
+ mStatusBarStateController.setState(KEYGUARD);
+
+ // Fling expanded (cancelling the keyguard exit swipe). We should notify keyguard state that
+ // the fling occurred and did not dismiss the keyguard.
+ mNotificationPanelViewController.flingToHeight(
+ 0f, true /* expand */, 1000f, 1f, false);
+ verify(mKeyguardStateController).notifyPanelFlingStart(false /* dismissKeyguard */);
+
+ // Fling un-expanded, which is a keyguard exit fling when we're in KEYGUARD state.
+ mNotificationPanelViewController.flingToHeight(
+ 0f, false /* expand */, 1000f, 1f, false);
+ verify(mKeyguardStateController).notifyPanelFlingStart(true /* dismissKeyguard */);
+ }
+
+ @Test
+ public void testCancelSwipeWhileLocked_notifiesKeyguardState() {
+ mStatusBarStateController.setState(KEYGUARD);
+
+ mNotificationPanelViewController.setOverExpansion(100f, true);
+
+ // Fling expanded (cancelling the keyguard exit swipe). We should notify keyguard state that
+ // the fling occurred and did not dismiss the keyguard.
+ mNotificationPanelViewController.flingToHeight(
+ 0f, true /* expand */, 1000f, 1f, false);
+ mNotificationPanelViewController.cancelHeightAnimator();
+ verify(mKeyguardStateController).notifyPanelFlingEnd();
+ }
+
private View newViewWithId(int id) {
View view = new View(mContext);
view.setId(id);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
index 4b8eec4..3238430 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
@@ -134,6 +134,19 @@
}
@Test
+ public void attach_animatingKeyguardAndSurface_wallpaperVisible() {
+ clearInvocations(mWindowManager);
+ when(mKeyguardViewMediator.isShowingAndNotOccluded()).thenReturn(true);
+ when(mKeyguardViewMediator
+ .isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe())
+ .thenReturn(true);
+ mNotificationShadeWindowController.attach();
+
+ verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
+ assertThat((mLayoutParameters.getValue().flags & FLAG_SHOW_WALLPAPER) != 0).isTrue();
+ }
+
+ @Test
public void setBackgroundBlurRadius_expandedWithBlurs() {
mNotificationShadeWindowController.setBackgroundBlurRadius(10);
verify(mNotificationShadeWindowView).setVisibility(eq(View.VISIBLE));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 8633eb4..7dcfc6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -49,8 +49,8 @@
import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.scrim.ScrimView;
import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -69,6 +69,7 @@
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -91,7 +92,7 @@
@Mock
private AlarmManager mAlarmManager;
@Mock
- private DozeParameters mDozeParamenters;
+ private DozeParameters mDozeParameters;
@Mock
LightBarController mLightBarController;
@Mock
@@ -200,8 +201,8 @@
return null;
}).when(mScrimBehind).postOnAnimationDelayed(any(Runnable.class), anyLong());
- when(mDozeParamenters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled);
- when(mDozeParamenters.getDisplayNeedsBlanking()).thenReturn(true);
+ when(mDozeParameters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled);
+ when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
doAnswer((Answer<Void>) invocation -> {
mScrimState = invocation.getArgument(0);
@@ -220,7 +221,7 @@
when(mDockManager.isDocked()).thenReturn(false);
mScrimController = new ScrimController(mLightBarController,
- mDozeParamenters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
+ mDozeParameters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
mDockManager, mConfigurationController, mFeatureFlags,
new FakeExecutor(new FakeSystemClock()));
@@ -238,6 +239,10 @@
@After
public void tearDown() {
finishAnimationsImmediately();
+ Arrays.stream(ScrimState.values()).forEach((scrim) -> {
+ scrim.setAodFrontScrimAlpha(0f);
+ scrim.setClipQsScrim(false);
+ });
DejankUtils.setImmediate(false);
}
@@ -259,9 +264,30 @@
@Test
public void transitionToShadeLocked() {
mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+ mScrimController.setQsPosition(1f, 0);
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
+ mNotificationsScrim, OPAQUE,
+ mScrimInFront, TRANSPARENT,
+ mScrimBehind, OPAQUE));
+
+ assertScrimTinted(Map.of(
+ mScrimInFront, false,
+ mScrimBehind, true,
+ mScrimForBubble, false
+ ));
+ }
+
+ @Test
+ public void transitionToShadeLocked_clippingQs() {
+ mScrimController.setClipsQsScrim(true);
+ mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+ mScrimController.setQsPosition(1f, 0);
+ finishAnimationsImmediately();
+
+ assertScrimAlpha(Map.of(
+ mNotificationsScrim, OPAQUE,
mScrimInFront, TRANSPARENT,
mScrimBehind, OPAQUE));
@@ -403,9 +429,6 @@
mScrimController.setAodFrontScrimAlpha(0.3f);
Assert.assertEquals(ScrimState.AOD.getFrontAlpha(), mScrimInFront.getViewAlpha(), 0.001f);
Assert.assertNotEquals(0.3f, mScrimInFront.getViewAlpha(), 0.001f);
-
- // Reset value since enums are static.
- mScrimController.setAodFrontScrimAlpha(0f);
}
@Test
@@ -500,11 +523,34 @@
// Back scrim should be visible without tint
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
mScrimBehind, OPAQUE));
assertScrimTinted(Map.of(
mScrimInFront, false,
mScrimBehind, false,
+ mNotificationsScrim, false,
+ mScrimForBubble, false
+ ));
+ }
+
+ @Test
+ public void transitionToKeyguardBouncer_clippingQs() {
+ mScrimController.setClipsQsScrim(true);
+ mScrimController.transitionTo(ScrimState.BOUNCER);
+ finishAnimationsImmediately();
+ // Front scrim should be transparent
+ // Back scrim should be clipping QS
+ // Notif scrim should be visible without tint
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, OPAQUE,
+ mScrimBehind, OPAQUE));
+
+ assertScrimTinted(Map.of(
+ mScrimInFront, false,
+ mScrimBehind, true,
+ mNotificationsScrim, false,
mScrimForBubble, false
));
}
@@ -530,9 +576,11 @@
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
mScrimBehind, TRANSPARENT));
assertScrimTinted(Map.of(
+ mNotificationsScrim, false,
mScrimInFront, false,
mScrimBehind, true,
mScrimForBubble, false
@@ -542,6 +590,7 @@
mScrimController.setPanelExpansion(0.5f);
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, SEMI_TRANSPARENT,
mScrimBehind, SEMI_TRANSPARENT));
}
@@ -553,7 +602,7 @@
assertScrimTinted(Map.of(
mScrimInFront, false,
mScrimBehind, false,
- mScrimForBubble, false
+ mScrimForBubble, true
));
// Front scrim should be transparent
@@ -617,6 +666,32 @@
}
@Test
+ public void qsExpansion_clippingQs() {
+ reset(mScrimBehind);
+ mScrimController.setClipsQsScrim(true);
+ mScrimController.setQsPosition(1f, 999 /* value doesn't matter */);
+ finishAnimationsImmediately();
+
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mScrimBehind, OPAQUE,
+ mNotificationsScrim, OPAQUE));
+ }
+
+ @Test
+ public void qsExpansion_half_clippingQs() {
+ reset(mScrimBehind);
+ mScrimController.setClipsQsScrim(true);
+ mScrimController.setQsPosition(0.5f, 999 /* value doesn't matter */);
+ finishAnimationsImmediately();
+
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mScrimBehind, OPAQUE,
+ mNotificationsScrim, SEMI_TRANSPARENT));
+ }
+
+ @Test
public void panelExpansionAffectsAlpha() {
mScrimController.setPanelExpansion(0f);
mScrimController.setPanelExpansion(0.5f);
@@ -919,13 +994,13 @@
@Test
public void testAnimatesTransitionToAod() {
- when(mDozeParamenters.shouldControlScreenOff()).thenReturn(false);
+ when(mDozeParameters.shouldControlScreenOff()).thenReturn(false);
ScrimState.AOD.prepare(ScrimState.KEYGUARD);
Assert.assertFalse("No animation when ColorFade kicks in",
ScrimState.AOD.getAnimateChange());
- reset(mDozeParamenters);
- when(mDozeParamenters.shouldControlScreenOff()).thenReturn(true);
+ reset(mDozeParameters);
+ when(mDozeParameters.shouldControlScreenOff()).thenReturn(true);
ScrimState.AOD.prepare(ScrimState.KEYGUARD);
Assert.assertTrue("Animate scrims when ColorFade won't be triggered",
ScrimState.AOD.getAnimateChange());
@@ -977,6 +1052,7 @@
mScrimController.setPanelExpansion(0.5f);
// notifications scrim alpha change require calling setQsPosition
mScrimController.setQsPosition(0, 300);
+ finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mScrimBehind, SEMI_TRANSPARENT,
@@ -985,6 +1061,21 @@
}
@Test
+ public void testScrimsVisible_whenShadeVisible_clippingQs() {
+ mScrimController.setClipsQsScrim(true);
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+ mScrimController.setPanelExpansion(0.5f);
+ // notifications scrim alpha change require calling setQsPosition
+ mScrimController.setQsPosition(0.5f, 300);
+ finishAnimationsImmediately();
+
+ assertScrimAlpha(Map.of(
+ mScrimBehind, OPAQUE,
+ mNotificationsScrim, SEMI_TRANSPARENT,
+ mScrimInFront, TRANSPARENT));
+ }
+
+ @Test
public void testScrimsVisible_whenShadeVisibleOnLockscreen() {
mScrimController.transitionTo(ScrimState.KEYGUARD);
mScrimController.setQsPosition(0.5f, 300);
@@ -1008,8 +1099,6 @@
}
private void assertScrimTinted(Map<ScrimView, Boolean> scrimToTint) {
- // notifications scrim should have always transparent tint
- assertScrimTint(mNotificationsScrim, false);
scrimToTint.forEach((scrim, hasTint) -> assertScrimTint(scrim, hasTint));
}
@@ -1047,6 +1136,12 @@
}
scrimToAlpha.forEach((scrimView, alpha) -> assertScrimAlpha(scrimView, alpha));
+ // When clipping, QS scrim should not affect combined visibility.
+ if (mScrimController.getClipQsScrim() && scrimToAlpha.get(mScrimBehind) == OPAQUE) {
+ scrimToAlpha = new HashMap<>(scrimToAlpha);
+ scrimToAlpha.remove(mScrimBehind);
+ }
+
// Check combined scrim visibility.
final int visibility;
if (scrimToAlpha.values().contains(OPAQUE)) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 11f96c8..8c8212c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -86,6 +86,7 @@
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -271,6 +272,7 @@
@Mock private TunerService mTunerService;
@Mock private FeatureFlags mFeatureFlags;
@Mock private IWallpaperManager mWallpaperManager;
+ @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private ShadeController mShadeController;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private InitController mInitController = new InitController();
@@ -439,7 +441,8 @@
mAnimationScheduler,
mDotViewController,
mTunerService,
- mFeatureFlags);
+ mFeatureFlags,
+ mKeyguardUnlockAnimationController);
when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class),
any(NotificationPanelViewController.class), any(BiometricUnlockController.class),
any(ViewGroup.class), any(KeyguardBypassController.class)))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
index e57bbc1..53a2efc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
@@ -143,4 +143,14 @@
verify(callback).onUnlockedChanged();
}
+ @Test
+ public void testKeyguardDismissAmountCallbackInvoked() {
+ KeyguardStateController.Callback callback = mock(KeyguardStateController.Callback.class);
+ mKeyguardStateController.addCallback(callback);
+
+ mKeyguardStateController.notifyKeyguardDismissAmountChanged(100f, false);
+
+ verify(callback).onKeyguardDismissAmountChanged();
+ }
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
index 26cac29..5fb779a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
@@ -92,4 +92,39 @@
public long calculateGoingToFullShadeDelay() {
return 0;
}
+
+ @Override
+ public float getDismissAmount() {
+ return 0;
+ }
+
+ @Override
+ public boolean isDismissingFromSwipe() {
+ return false;
+ }
+
+ @Override
+ public boolean isFlingingToDismissKeyguard() {
+ return false;
+ }
+
+ @Override
+ public boolean isFlingingToDismissKeyguardDuringSwipeGesture() {
+ return false;
+ }
+
+ @Override
+ public boolean isSnappingKeyguardBackAfterSwipe() {
+ return false;
+ }
+
+ @Override
+ public void notifyPanelFlingStart(boolean dismiss) {
+
+ }
+
+ @Override
+ public void notifyPanelFlingEnd() {
+
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 9fc1df7..6e2e4cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -112,6 +112,7 @@
import com.android.wm.shell.bubbles.BubbleStackView;
import com.android.wm.shell.bubbles.BubbleViewInfoTask;
import com.android.wm.shell.bubbles.Bubbles;
+import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -315,6 +316,7 @@
mTaskStackListener,
mShellTaskOrganizer,
mPositioner,
+ mock(DisplayController.class),
syncExecutor,
mock(Handler.class));
mBubbleController.setExpandListener(mBubbleExpandListener);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index 89825d2..9339f81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -92,6 +92,7 @@
import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubbleStackView;
import com.android.wm.shell.bubbles.Bubbles;
+import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -259,6 +260,7 @@
mTaskStackListener,
mShellTaskOrganizer,
mPositioner,
+ mock(DisplayController.class),
syncExecutor,
mock(Handler.class));
mBubbleController.setExpandListener(mBubbleExpandListener);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
index a9a558d..cd5aa9a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
@@ -29,6 +29,7 @@
import com.android.wm.shell.bubbles.BubbleDataRepository;
import com.android.wm.shell.bubbles.BubbleLogger;
import com.android.wm.shell.bubbles.BubblePositioner;
+import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -51,12 +52,13 @@
TaskStackListenerImpl taskStackListener,
ShellTaskOrganizer shellTaskOrganizer,
BubblePositioner positioner,
+ DisplayController displayController,
ShellExecutor shellMainExecutor,
Handler shellMainHandler) {
super(context, data, Runnable::run, floatingContentCoordinator, dataRepository,
statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
- bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, shellMainExecutor,
- shellMainHandler);
+ bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, displayController,
+ shellMainExecutor, shellMainHandler);
setInflateSynchronously(true);
initialize();
}
diff --git a/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp b/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp
index a18ebb3..690d0a0 100644
--- a/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp
+++ b/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp
@@ -26,6 +26,5 @@
runtime_resource_overlay {
name: "IconPackVictorThemePickerOverlay",
theme: "IconPackVictorThemePicker",
- certificate: "platform",
product_specific: true,
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 57e5bb2..f1dcdff 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -450,7 +450,7 @@
return;
}
mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
- maybeRequestFillLocked();
+ maybeRequestFillFromServiceLocked();
viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
}
} : null;
@@ -462,7 +462,7 @@
mPendingInlineSuggestionsRequest = inlineRequest;
}
- void maybeRequestFillLocked() {
+ void maybeRequestFillFromServiceLocked() {
if (mPendingFillRequest == null) {
return;
}
@@ -472,9 +472,12 @@
return;
}
- mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
- mPendingFillRequest.getFillContexts(), mPendingFillRequest.getClientState(),
- mPendingFillRequest.getFlags(), mPendingInlineSuggestionsRequest);
+ if (mPendingInlineSuggestionsRequest.isServiceSupported()) {
+ mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
+ mPendingFillRequest.getFillContexts(),
+ mPendingFillRequest.getClientState(),
+ mPendingFillRequest.getFlags(), mPendingInlineSuggestionsRequest);
+ }
}
mRemoteFillService.onFillRequest(mPendingFillRequest);
@@ -581,7 +584,7 @@
/*inlineSuggestionsRequest=*/null);
mPendingFillRequest = request;
- maybeRequestFillLocked();
+ maybeRequestFillFromServiceLocked();
}
if (mActivityToken != null) {
@@ -3188,6 +3191,17 @@
return false;
}
+ final InlineSuggestionsRequest request = inlineSuggestionsRequest.get();
+ if (mSessionFlags.mClientSuggestionsEnabled && !request.isClientSupported()
+ || !mSessionFlags.mClientSuggestionsEnabled && !request.isServiceSupported()) {
+ if (sDebug) {
+ Slog.d(TAG, "Inline suggestions not supported for "
+ + (mSessionFlags.mClientSuggestionsEnabled ? "client" : "service")
+ + ". Falling back to dropdown.");
+ }
+ return false;
+ }
+
final RemoteInlineSuggestionRenderService remoteRenderService =
mService.getRemoteInlineSuggestionRenderServiceLocked();
if (remoteRenderService == null) {
@@ -3196,7 +3210,7 @@
}
final InlineFillUi.InlineFillUiInfo inlineFillUiInfo =
- new InlineFillUi.InlineFillUiInfo(inlineSuggestionsRequest.get(), focusedId,
+ new InlineFillUi.InlineFillUiInfo(request, focusedId,
filterText, remoteRenderService, userId, id);
InlineFillUi inlineFillUi = InlineFillUi.forAutofill(inlineFillUiInfo, response,
new InlineFillUi.InlineSuggestionUiCallback() {
@@ -3809,6 +3823,10 @@
mContexts = new ArrayList<>(1);
}
+ if (inlineSuggestionsRequest != null && !inlineSuggestionsRequest.isClientSupported()) {
+ inlineSuggestionsRequest = null;
+ }
+
mClientSuggestionsSession.onFillRequest(requestId, inlineSuggestionsRequest, mFlags);
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 84e675e..c5246c7 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.content.PermissionChecker.PERMISSION_HARD_DENIED;
+import static android.content.PermissionChecker.PID_UNKNOWN;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
@@ -45,6 +46,7 @@
import android.bluetooth.IBluetoothProfileServiceConnection;
import android.bluetooth.IBluetoothStateChangeCallback;
import android.content.ActivityNotFoundException;
+import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -306,13 +308,13 @@
DELAY_BEFORE_RESTART_DUE_TO_INIT_FLAGS_CHANGED_MS);
}
- public boolean onFactoryReset() {
+ public boolean onFactoryReset(AttributionSource attributionSource) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
"Need BLUETOOTH_PRIVILEGED permission");
final long token = Binder.clearCallingIdentity();
try {
- return onFactoryResetInternal();
+ return onFactoryResetInternal(attributionSource);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -322,7 +324,7 @@
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
})
- private boolean onFactoryResetInternal() {
+ private boolean onFactoryResetInternal(AttributionSource attributionSource) {
// Wait for stable state if bluetooth is temporary state.
int state = getState();
if (state == BluetoothAdapter.STATE_BLE_TURNING_ON
@@ -351,7 +353,7 @@
addActiveLog(
BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET,
mContext.getPackageName(), false);
- mBluetooth.disable(mContext.getAttributionSource());
+ mBluetooth.disable(attributionSource);
return true;
}
} catch (RemoteException e) {
@@ -947,7 +949,8 @@
}
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private boolean checkBluetoothPermissions(String packageName, boolean requireForeground) {
+ private boolean checkBluetoothPermissions(AttributionSource attributionSource, String message,
+ boolean requireForeground) {
if (isBluetoothDisallowed()) {
if (DBG) {
Slog.d(TAG, "checkBluetoothPermissions: bluetooth disallowed");
@@ -958,22 +961,24 @@
final int callingUid = Binder.getCallingUid();
final boolean isCallerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID;
if (!isCallerSystem) {
- checkPackage(callingUid, packageName);
+ checkPackage(callingUid, attributionSource.getPackageName());
if (requireForeground && !checkIfCallerIsForegroundUser()) {
Slog.w(TAG, "Not allowed for non-active and non system user");
return false;
}
- if (!checkConnectPermissionForPreflight(mContext)) {
+ if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, message)) {
return false;
}
}
return true;
}
- public boolean enableBle(String packageName, IBinder token) throws RemoteException {
- if (!checkBluetoothPermissions(packageName, false)) {
+ public boolean enableBle(AttributionSource attributionSource, IBinder token)
+ throws RemoteException {
+ final String packageName = attributionSource.getPackageName();
+ if (!checkBluetoothPermissions(attributionSource, "enableBle", false)) {
if (DBG) {
Slog.d(TAG, "enableBle(): bluetooth disallowed");
}
@@ -1003,8 +1008,10 @@
}
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public boolean disableBle(String packageName, IBinder token) throws RemoteException {
- if (!checkBluetoothPermissions(packageName, false)) {
+ public boolean disableBle(AttributionSource attributionSource, IBinder token)
+ throws RemoteException {
+ final String packageName = attributionSource.getPackageName();
+ if (!checkBluetoothPermissions(attributionSource, "disableBle", false)) {
if (DBG) {
Slog.d(TAG, "disableBLE(): bluetooth disallowed");
}
@@ -1103,7 +1110,7 @@
if (isBleAppPresent()) {
// Need to stay at BLE ON. Disconnect all Gatt connections
try {
- mBluetoothGatt.unregAll();
+ mBluetoothGatt.unregAll(mContext.getAttributionSource());
} catch (RemoteException e) {
Slog.e(TAG, "Unable to disconnect all apps.", e);
}
@@ -1122,8 +1129,9 @@
}
- public boolean enableNoAutoConnect(String packageName) {
- if (!checkBluetoothPermissions(packageName, false)) {
+ public boolean enableNoAutoConnect(AttributionSource attributionSource) {
+ final String packageName = attributionSource.getPackageName();
+ if (!checkBluetoothPermissions(attributionSource, "enableNoAutoConnect", false)) {
if (DBG) {
Slog.d(TAG, "enableNoAutoConnect(): not enabling - bluetooth disallowed");
}
@@ -1149,8 +1157,9 @@
return true;
}
- public boolean enable(String packageName) throws RemoteException {
- if (!checkBluetoothPermissions(packageName, true)) {
+ public boolean enable(AttributionSource attributionSource) throws RemoteException {
+ final String packageName = attributionSource.getPackageName();
+ if (!checkBluetoothPermissions(attributionSource, "enable", true)) {
if (DBG) {
Slog.d(TAG, "enable(): not enabling - bluetooth disallowed");
}
@@ -1183,8 +1192,10 @@
return true;
}
- public boolean disable(String packageName, boolean persist) throws RemoteException {
- if (!checkBluetoothPermissions(packageName, true)) {
+ public boolean disable(AttributionSource attributionSource, boolean persist)
+ throws RemoteException {
+ final String packageName = attributionSource.getPackageName();
+ if (!checkBluetoothPermissions(attributionSource, "disable", true)) {
if (DBG) {
Slog.d(TAG, "disable(): not disabling - bluetooth disallowed");
}
@@ -1700,8 +1711,8 @@
}
}
- public String getAddress() {
- if (!checkConnectPermissionForPreflight(mContext)) {
+ public String getAddress(AttributionSource attributionSource) {
+ if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, "getAddress")) {
return null;
}
@@ -1734,8 +1745,8 @@
return mAddress;
}
- public String getName() {
- if (!checkConnectPermissionForPreflight(mContext)) {
+ public String getName(AttributionSource attributionSource) {
+ if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, "getName")) {
return null;
}
@@ -2879,6 +2890,25 @@
}
}
+ private static boolean checkPermissionForDataDelivery(Context context, String permission,
+ AttributionSource attributionSource, String message) {
+ final int result = PermissionChecker.checkPermissionForDataDeliveryFromDataSource(
+ context, permission, PID_UNKNOWN,
+ new AttributionSource(context.getAttributionSource(), attributionSource), message);
+ if (result == PERMISSION_GRANTED) {
+ return true;
+ }
+
+ final String msg = "Need " + permission + " permission for " + attributionSource + ": "
+ + message;
+ if (result == PERMISSION_HARD_DENIED) {
+ throw new SecurityException(msg);
+ } else {
+ Log.w(TAG, msg);
+ return false;
+ }
+ }
+
/**
* Returns true if the BLUETOOTH_CONNECT permission is granted for the calling app. Returns
* false if the result is a soft denial. Throws SecurityException if the result is a hard
@@ -2887,13 +2917,10 @@
* <p>Should be used in situations where the app op should not be noted.
*/
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private static boolean checkConnectPermissionForPreflight(Context context) {
- int permissionCheckResult = PermissionChecker.checkCallingOrSelfPermissionForPreflight(
- context, BLUETOOTH_CONNECT);
- if (permissionCheckResult == PERMISSION_HARD_DENIED) {
- throw new SecurityException("Need BLUETOOTH_CONNECT permission");
- }
- return permissionCheckResult == PERMISSION_GRANTED;
+ public static boolean checkConnectPermissionForDataDelivery(
+ Context context, AttributionSource attributionSource, String message) {
+ return checkPermissionForDataDelivery(context, BLUETOOTH_CONNECT,
+ attributionSource, message);
}
static @NonNull Bundle getTempAllowlistBroadcastOptions() {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 81f5dc8c..8e12cb2 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -15,6 +15,7 @@
*/
package com.android.server;
+
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
import static android.content.pm.PackageManager.FEATURE_WATCH;
@@ -33,7 +34,6 @@
import static android.net.ConnectivityManager.BLOCKED_REASON_LOCKDOWN_VPN;
import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
@@ -53,6 +53,7 @@
import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeValid;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
@@ -8672,8 +8673,7 @@
// restore private DNS settings to default mode (opportunistic)
if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS)) {
- Settings.Global.putString(mContext.getContentResolver(),
- ConnectivitySettingsManager.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OPPORTUNISTIC);
+ ConnectivitySettingsManager.setPrivateDnsMode(mContext, PRIVATE_DNS_MODE_OPPORTUNISTIC);
}
Settings.Global.putString(mContext.getContentResolver(),
@@ -9694,7 +9694,8 @@
// request.
final ArrayList<NetworkRequest> nrs = new ArrayList<>();
nrs.add(createNetworkRequest(NetworkRequest.Type.REQUEST, pref.capabilities));
- nrs.add(createDefaultRequest());
+ nrs.add(createDefaultInternetRequestForTransport(
+ TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT));
setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids()));
final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs);
result.add(nri);
@@ -9999,7 +10000,8 @@
case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID:
requests.add(createUnmeteredNetworkRequest());
requests.add(createOemPaidNetworkRequest());
- requests.add(createDefaultRequest());
+ requests.add(createDefaultInternetRequestForTransport(
+ TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT));
break;
case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK:
requests.add(createUnmeteredNetworkRequest());
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 08bff81..8561042 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -935,9 +935,7 @@
int mapSize = 0;
try {
- int openFlags = (OsConstants.O_RDONLY |
- OsConstants.O_CLOEXEC |
- OsConstants.O_NOFOLLOW);
+ int openFlags = (OsConstants.O_RDONLY | OsConstants.O_CLOEXEC);
fd = Os.open(fileToPin, openFlags, 0);
mapSize = (int) Math.min(Os.fstat(fd).st_size, Integer.MAX_VALUE);
address = Os.mmap(0, mapSize,
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index ee3530a..edf832f 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -2072,7 +2072,8 @@
private void notifyCellLocationForSubscriber(int subId, CellIdentity cellIdentity,
boolean hasUserSwitched) {
- log("notifyCellLocationForSubscriber: subId=" + subId + " cellIdentity=" + cellIdentity);
+ log("notifyCellLocationForSubscriber: subId=" + subId + " cellIdentity="
+ + Rlog.pii(DBG || VDBG || DBG_LOC, cellIdentity));
if (!checkNotifyPermission("notifyCellLocation()")) {
return;
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index c7994c3..206f135ae 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -70,6 +70,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UptimeMillisLong;
@@ -3078,6 +3079,18 @@
+ ", uid=" + callingUid
+ " requires " + r.permission);
return new ServiceLookupResult(null, r.permission);
+ } else if (Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(r.permission)
+ && callingUid != Process.SYSTEM_UID) {
+ // Hotword detection must run in its own sandbox, and we don't even trust
+ // its enclosing application to bind to it - only the system.
+ // TODO(b/185746653) remove this special case and generalize
+ Slog.w(TAG, "Permission Denial: Accessing service " + r.shortInstanceName
+ + " from pid=" + callingPid
+ + ", uid=" + callingUid
+ + " requiring permission " + r.permission
+ + " can only be bound to from the system.");
+ return new ServiceLookupResult(null, "can only be bound to "
+ + "by the system.");
} else if (r.permission != null && callingPackage != null) {
final int opCode = AppOpsManager.permissionToOpCode(r.permission);
if (opCode != AppOpsManager.OP_NONE && mAm.getAppOpsManager().checkOpNoThrow(
@@ -5920,6 +5933,10 @@
* @param durationMs Only meaningful for EXIT event, the duration from ENTER and EXIT state.
*/
private void logForegroundServiceStateChanged(ServiceRecord r, int state, int durationMs) {
+ if (!ActivityManagerUtils.shouldSamplePackageForAtom(
+ r.packageName, mAm.mConstants.mDefaultFgsAtomSampleRate)) {
+ return;
+ }
FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
r.appInfo.uid,
r.shortInstanceName,
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index c8363dd..bf57452 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -97,6 +97,7 @@
static final String KEY_BOOT_TIME_TEMP_ALLOWLIST_DURATION = "boot_time_temp_allowlist_duration";
static final String KEY_FG_TO_BG_FGS_GRACE_DURATION = "fg_to_bg_fgs_grace_duration";
static final String KEY_FGS_START_FOREGROUND_TIMEOUT = "fgs_start_foreground_timeout";
+ static final String KEY_FGS_ATOM_SAMPLE_RATE = "fgs_atom_sample_rate";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -137,6 +138,7 @@
private static final int DEFAULT_BOOT_TIME_TEMP_ALLOWLIST_DURATION = 10 * 1000;
private static final long DEFAULT_FG_TO_BG_FGS_GRACE_DURATION = 5 * 1000;
private static final int DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS = 10 * 1000;
+ private static final float DEFAULT_FGS_ATOM_SAMPLE_RATE = 1; // 100 %
// Flag stored in the DeviceConfig API.
/**
@@ -430,6 +432,13 @@
*/
volatile long mFgsStartForegroundTimeoutMs = DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS;
+ /**
+ * Sample rate for the FGS westworld atom.
+ *
+ * If the value is 0.1, 10% of the installed packages would be sampled.
+ */
+ volatile float mDefaultFgsAtomSampleRate = DEFAULT_FGS_ATOM_SAMPLE_RATE;
+
private final ActivityManagerService mService;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -629,6 +638,9 @@
case KEY_FGS_START_FOREGROUND_TIMEOUT:
updateFgsStartForegroundTimeout();
break;
+ case KEY_FGS_ATOM_SAMPLE_RATE:
+ updateFgsAtomSamplePercent();
+ break;
default:
break;
}
@@ -933,6 +945,13 @@
DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS);
}
+ private void updateFgsAtomSamplePercent() {
+ mDefaultFgsAtomSampleRate = DeviceConfig.getFloat(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_FGS_ATOM_SAMPLE_RATE,
+ DEFAULT_FGS_ATOM_SAMPLE_RATE);
+ }
+
private void updateImperceptibleKillExemptions() {
IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.clear();
IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.addAll(mDefaultImperceptibleKillExemptPackages);
@@ -1145,6 +1164,8 @@
pw.println(mFlagFgsStartRestrictionEnabled);
pw.print(" "); pw.print(KEY_DEFAULT_FGS_STARTS_RESTRICTION_CHECK_CALLER_TARGET_SDK);
pw.print("="); pw.println(mFgsStartRestrictionCheckCallerTargetSdk);
+ pw.print(" "); pw.print(KEY_FGS_ATOM_SAMPLE_RATE);
+ pw.print("="); pw.println(mDefaultFgsAtomSampleRate);
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9568fa5..00b13b1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7775,7 +7775,17 @@
: ServerProtoEnums.ERROR_SOURCE_UNKNOWN,
incrementalMetrics != null /* isIncremental */, loadingProgress,
incrementalMetrics != null ? incrementalMetrics.getMillisSinceOldestPendingRead()
- : -1
+ : -1,
+ 0 /* storage_health_code */,
+ 0 /* data_loader_status_code */,
+ false /* read_logs_enabled */,
+ 0 /* millis_since_last_data_loader_bind */,
+ 0 /* data_loader_bind_delay_millis */,
+ 0 /* total_delayed_reads */,
+ 0 /* total_failed_reads */,
+ 0 /* last_read_error_uid */,
+ 0 /* last_read_error_millis_since */,
+ 0 /* last_read_error_code */
);
final int relaunchReason = r == null ? RELAUNCH_REASON_NONE
diff --git a/services/core/java/com/android/server/am/ActivityManagerUtils.java b/services/core/java/com/android/server/am/ActivityManagerUtils.java
new file mode 100644
index 0000000..dd24148
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityManagerUtils.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.am;
+
+import android.app.ActivityThread;
+import android.provider.Settings;
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * To store random utility methods...
+ */
+public class ActivityManagerUtils {
+ private ActivityManagerUtils() {
+ }
+
+ private static Integer sAndroidIdHash;
+
+ @GuardedBy("sHashCache")
+ private static final ArrayMap<String, Integer> sHashCache = new ArrayMap<>();
+
+ private static String sInjectedAndroidId;
+
+ /** Used by the unit tests to inject an android ID. Do not set in the prod code. */
+ @VisibleForTesting
+ static void injectAndroidIdForTest(String androidId) {
+ sInjectedAndroidId = androidId;
+ sAndroidIdHash = null;
+ }
+
+ /**
+ * Return a hash between [0, MAX_VALUE] generated from the android ID.
+ */
+ @VisibleForTesting
+ static int getAndroidIdHash() {
+ // No synchronization is required. Double-initialization is fine here.
+ if (sAndroidIdHash == null) {
+ final String androidId = Settings.Secure.getString(
+ ActivityThread.currentApplication().getContentResolver(),
+ Settings.Secure.ANDROID_ID);
+ sAndroidIdHash = getUnsignedHashUnCached(
+ sInjectedAndroidId != null ? sInjectedAndroidId : androidId);
+ }
+ return sAndroidIdHash;
+ }
+
+ /**
+ * Return a hash between [0, MAX_VALUE] generated from a package name, using a cache.
+ *
+ * Because all the results are cached, do not use it for dynamically generated strings.
+ */
+ @VisibleForTesting
+ static int getUnsignedHashCached(String s) {
+ synchronized (sHashCache) {
+ final Integer cached = sHashCache.get(s);
+ if (cached != null) {
+ return cached;
+ }
+ final int hash = getUnsignedHashUnCached(s);
+ sHashCache.put(s.intern(), hash);
+ return hash;
+ }
+ }
+
+ /**
+ * Return a hash between [0, MAX_VALUE] generated from a package name.
+ */
+ private static int getUnsignedHashUnCached(String s) {
+ try {
+ final MessageDigest digest = MessageDigest.getInstance("SHA-1");
+ digest.update(s.getBytes());
+ return unsignedIntFromBytes(digest.digest());
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @VisibleForTesting
+ static int unsignedIntFromBytes(byte[] longEnoughBytes) {
+ return (extractByte(longEnoughBytes, 0)
+ | extractByte(longEnoughBytes, 1)
+ | extractByte(longEnoughBytes, 2)
+ | extractByte(longEnoughBytes, 3))
+ & 0x7FFF_FFFF;
+ }
+
+ private static int extractByte(byte[] bytes, int index) {
+ return (((int) bytes[index]) & 0xFF) << (index * 8);
+ }
+
+ /**
+ * @return whether a package should be logged, using a random value based on the ANDROID_ID,
+ * with a given sampling rate.
+ */
+ public static boolean shouldSamplePackageForAtom(String packageName, float rate) {
+ if (rate <= 0) {
+ return false;
+ }
+ if (rate >= 1) {
+ return true;
+ }
+ final int hash = getUnsignedHashCached(packageName) ^ getAndroidIdHash();
+
+ return (((double) hash) / Integer.MAX_VALUE) <= rate;
+ }
+}
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 6ff3bf6..167ed86 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -432,7 +432,17 @@
(mApp.info != null) ? mApp.info.packageName : "",
incrementalMetrics != null /* isIncremental */, loadingProgress,
incrementalMetrics != null ? incrementalMetrics.getMillisSinceOldestPendingRead()
- : -1);
+ : -1,
+ 0 /* storage_health_code */,
+ 0 /* data_loader_status_code */,
+ false /* read_logs_enabled */,
+ 0 /* millis_since_last_data_loader_bind */,
+ 0 /* data_loader_bind_delay_millis */,
+ 0 /* total_delayed_reads */,
+ 0 /* total_failed_reads */,
+ 0 /* last_read_error_uid */,
+ 0 /* last_read_error_millis_since */,
+ 0 /* last_read_error_code */);
final ProcessRecord parentPr = parentProcess != null
? (ProcessRecord) parentProcess.mOwner : null;
mService.addErrorToDropBox("anr", mApp, mApp.processName, activityShortComponentName,
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 88e47a0..6f73985 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -30,12 +30,14 @@
import static android.hardware.biometrics.BiometricManager.Authenticators;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.IAuthService;
-import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceReceiver;
@@ -44,7 +46,11 @@
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorPropertiesInternal;
+import android.hardware.face.FaceSensorProperties;
+import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceService;
+import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.iris.IIrisService;
import android.os.Binder;
@@ -58,11 +64,10 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.server.SystemService;
-import com.android.server.biometrics.sensors.face.FaceAuthenticator;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintAuthenticator;
-import com.android.server.biometrics.sensors.iris.IrisAuthenticator;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -337,7 +342,7 @@
}
@Override
- public long[] getAuthenticatorIds() throws RemoteException {
+ public long[] getAuthenticatorIds(int userId) throws RemoteException {
// In this method, we're not checking whether the caller is permitted to use face
// API because current authenticator ID is leaked (in a more contrived way) via Android
// Keystore (android.security.keystore package): the user of that API can create a key
@@ -355,9 +360,13 @@
// method from inside app processes.
final int callingUserId = UserHandle.getCallingUserId();
+ if (userId != callingUserId) {
+ getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL,
+ "Must have " + USE_BIOMETRIC_INTERNAL + " permission.");
+ }
final long identity = Binder.clearCallingIdentity();
try {
- return mBiometricService.getAuthenticatorIds(callingUserId);
+ return mBiometricService.getAuthenticatorIds(userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -574,81 +583,119 @@
mImpl = new AuthServiceImpl();
}
+
+ /**
+ * Registration of all HIDL and AIDL biometric HALs starts here.
+ * The flow looks like this:
+ * AuthService
+ * └── .onStart()
+ * └── .registerAuthenticators(...)
+ * ├── FaceService.registerAuthenticators(...)
+ * │ └── for (p : serviceProviders)
+ * │ └── for (s : p.sensors)
+ * │ └── BiometricService.registerAuthenticator(s)
+ * │
+ * ├── FingerprintService.registerAuthenticators(...)
+ * │ └── for (p : serviceProviders)
+ * │ └── for (s : p.sensors)
+ * │ └── BiometricService.registerAuthenticator(s)
+ * │
+ * └── IrisService.registerAuthenticators(...)
+ * └── for (p : serviceProviders)
+ * └── for (s : p.sensors)
+ * └── BiometricService.registerAuthenticator(s)
+ */
@Override
public void onStart() {
mBiometricService = mInjector.getBiometricService();
+ final SensorConfig[] hidlConfigs;
if (!mInjector.isHidlDisabled(getContext())) {
- final String[] configs = mInjector.getConfiguration(getContext());
- for (String config : configs) {
- try {
- registerAuthenticator(new SensorConfig(config));
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- }
+ final String[] configStrings = mInjector.getConfiguration(getContext());
+ hidlConfigs = new SensorConfig[configStrings.length];
+ for (int i = 0; i < configStrings.length; ++i) {
+ hidlConfigs[i] = new SensorConfig(configStrings[i]);
}
+ } else {
+ hidlConfigs = null;
}
+ // Registers HIDL and AIDL authenticators, but only HIDL configs need to be provided.
+ registerAuthenticators(hidlConfigs);
+
mInjector.publishBinderService(this, mImpl);
}
- private void registerAuthenticator(SensorConfig config) throws RemoteException {
- Slog.d(TAG, "Registering ID: " + config.id
- + " Modality: " + config.modality
- + " Strength: " + config.strength);
+ /**
+ * Registers HIDL and AIDL authenticators for all of the available modalities.
+ *
+ * @param hidlSensors Array of {@link SensorConfig} configuration for all of the HIDL sensors
+ * available on the device. This array may contain configuration for
+ * different modalities and different sensors of the same modality in
+ * arbitrary order. Can be null if no HIDL sensors exist on the device.
+ */
+ private void registerAuthenticators(@Nullable SensorConfig[] hidlSensors) {
+ List<FingerprintSensorPropertiesInternal> hidlFingerprintSensors = new ArrayList<>();
+ List<FaceSensorPropertiesInternal> hidlFaceSensors = new ArrayList<>();
+ // Iris doesn't have IrisSensorPropertiesInternal, using SensorPropertiesInternal instead.
+ List<SensorPropertiesInternal> hidlIrisSensors = new ArrayList<>();
- final IBiometricAuthenticator.Stub authenticator;
+ if (hidlSensors != null) {
+ for (SensorConfig sensor : hidlSensors) {
+ Slog.d(TAG, "Registering HIDL ID: " + sensor.id + " Modality: " + sensor.modality
+ + " Strength: " + sensor.strength);
+ switch (sensor.modality) {
+ case TYPE_FINGERPRINT:
+ hidlFingerprintSensors.add(
+ getHidlFingerprintSensorProps(sensor.id, sensor.strength));
+ break;
- switch (config.modality) {
- case TYPE_FINGERPRINT:
- final IFingerprintService fingerprintService = mInjector.getFingerprintService();
- if (fingerprintService == null) {
- Slog.e(TAG, "Attempting to register with null FingerprintService."
- + " Please check your device configuration.");
- return;
+ case TYPE_FACE:
+ hidlFaceSensors.add(getHidlFaceSensorProps(sensor.id, sensor.strength));
+ break;
+
+ case TYPE_IRIS:
+ hidlIrisSensors.add(getHidlIrisSensorProps(sensor.id, sensor.strength));
+ break;
+
+ default:
+ Slog.e(TAG, "Unknown modality: " + sensor.modality);
}
-
- // Initialize this outside of FingerprintAuthenticator. Only HIDL HALs require
- // initialization from here. AIDL HALs are initialized by FingerprintService since
- // the HAL interface provides ID, strength, and other configuration information.
- fingerprintService.initializeConfiguration(config.id, config.strength);
- authenticator = new FingerprintAuthenticator(fingerprintService, config.id);
- break;
-
- case TYPE_FACE:
- final IFaceService faceService = mInjector.getFaceService();
- if (faceService == null) {
- Slog.e(TAG, "Attempting to register with null FaceService. Please check "
- + " your device configuration.");
- return;
- }
-
- // Initialize this outside of FingerprintAuthenticator. Only HIDL HALs require
- // initialization from here. AIDL HALs are initialized by FaceService since
- // the HAL interface provides ID, strength, and other configuration information.
- faceService.initializeConfiguration(config.id, config.strength);
- authenticator = new FaceAuthenticator(faceService, config.id);
- break;
-
- case TYPE_IRIS:
- final IIrisService irisService = mInjector.getIrisService();
- if (irisService == null) {
- Slog.e(TAG, "Attempting to register with null IrisService. Please check"
- + " your device configuration.");
- return;
- }
-
- irisService.initializeConfiguration(config.id, config.strength);
- authenticator = new IrisAuthenticator(irisService, config.id);
- break;
-
- default:
- Slog.e(TAG, "Unknown modality: " + config.modality);
- return;
+ }
}
- mBiometricService.registerAuthenticator(config.id, config.modality, config.strength,
- authenticator);
+ final IFingerprintService fingerprintService = mInjector.getFingerprintService();
+ if (fingerprintService != null) {
+ try {
+ fingerprintService.registerAuthenticators(hidlFingerprintSensors);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException when registering fingerprint authenticators", e);
+ }
+ } else if (hidlFingerprintSensors.size() > 0) {
+ Slog.e(TAG, "HIDL fingerprint configuration exists, but FingerprintService is null.");
+ }
+
+ final IFaceService faceService = mInjector.getFaceService();
+ if (faceService != null) {
+ try {
+ faceService.registerAuthenticators(hidlFaceSensors);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException when registering face authenticators", e);
+ }
+ } else if (hidlFaceSensors.size() > 0) {
+ Slog.e(TAG, "HIDL face configuration exists, but FaceService is null.");
+ }
+
+ final IIrisService irisService = mInjector.getIrisService();
+ if (irisService != null) {
+ try {
+ irisService.registerAuthenticators(hidlIrisSensors);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException when registering iris authenticators", e);
+ }
+ } else if (hidlIrisSensors.size() > 0) {
+ Slog.e(TAG, "HIDL iris configuration exists, but IrisService is null.");
+ }
}
private void checkInternalPermission() {
@@ -674,4 +721,72 @@
return modality == BiometricAuthenticator.TYPE_CREDENTIAL
? modality : (modality & ~BiometricAuthenticator.TYPE_CREDENTIAL);
}
+
+
+ private FingerprintSensorPropertiesInternal getHidlFingerprintSensorProps(int sensorId,
+ @BiometricManager.Authenticators.Types int strength) {
+ // The existence of config_udfps_sensor_props indicates that the sensor is UDFPS.
+ final int[] udfpsProps = getContext().getResources().getIntArray(
+ com.android.internal.R.array.config_udfps_sensor_props);
+
+ final boolean isUdfps = !ArrayUtils.isEmpty(udfpsProps);
+
+ // config_is_powerbutton_fps indicates whether device has a power button fingerprint sensor.
+ final boolean isPowerbuttonFps = getContext().getResources().getBoolean(
+ R.bool.config_is_powerbutton_fps);
+
+ final @FingerprintSensorProperties.SensorType int sensorType;
+ if (isUdfps) {
+ sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
+ } else if (isPowerbuttonFps) {
+ sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON;
+ } else {
+ sensorType = FingerprintSensorProperties.TYPE_REAR;
+ }
+
+ // IBiometricsFingerprint@2.1 does not manage timeout below the HAL, so the Gatekeeper HAT
+ // cannot be checked.
+ final boolean resetLockoutRequiresHardwareAuthToken = false;
+ final int maxEnrollmentsPerUser = getContext().getResources().getInteger(
+ R.integer.config_fingerprintMaxTemplatesPerUser);
+
+ final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+ if (isUdfps && udfpsProps.length == 3) {
+ return new FingerprintSensorPropertiesInternal(sensorId,
+ Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
+ componentInfo, sensorType, resetLockoutRequiresHardwareAuthToken, udfpsProps[0],
+ udfpsProps[1], udfpsProps[2]);
+ } else {
+ return new FingerprintSensorPropertiesInternal(sensorId,
+ Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
+ componentInfo, sensorType, resetLockoutRequiresHardwareAuthToken);
+ }
+ }
+
+ private FaceSensorPropertiesInternal getHidlFaceSensorProps(int sensorId,
+ @BiometricManager.Authenticators.Types int strength) {
+ final boolean supportsSelfIllumination = getContext().getResources().getBoolean(
+ R.bool.config_faceAuthSupportsSelfIllumination);
+ final int maxTemplatesAllowed = getContext().getResources().getInteger(
+ R.integer.config_faceMaxTemplatesPerUser);
+ final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+ final boolean supportsFaceDetect = false;
+ final boolean resetLockoutRequiresChallenge = true;
+ return new FaceSensorPropertiesInternal(sensorId,
+ Utils.authenticatorStrengthToPropertyStrength(strength), maxTemplatesAllowed,
+ componentInfo, FaceSensorProperties.TYPE_UNKNOWN, supportsFaceDetect,
+ supportsSelfIllumination, resetLockoutRequiresChallenge);
+ }
+
+ private SensorPropertiesInternal getHidlIrisSensorProps(int sensorId,
+ @BiometricManager.Authenticators.Types int strength) {
+ final int maxEnrollmentsPerUser = 1;
+ final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+ final boolean resetLockoutRequiresHardwareAuthToken = false;
+ final boolean resetLockoutRequiresChallenge = false;
+ return new SensorPropertiesInternal(sensorId,
+ Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
+ componentInfo, resetLockoutRequiresHardwareAuthToken,
+ resetLockoutRequiresChallenge);
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index f744374..fbf2492 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -17,6 +17,7 @@
package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricConstants;
import android.media.AudioAttributes;
@@ -26,6 +27,7 @@
import android.os.SystemClock;
import android.os.VibrationEffect;
import android.os.Vibrator;
+import android.text.TextUtils;
import android.util.Slog;
/**
@@ -43,6 +45,15 @@
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
+ private final VibrationEffect mEffectTick = VibrationEffect.get(VibrationEffect.EFFECT_TICK);
+ private final VibrationEffect mEffectTextureTick =
+ VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK);
+ private final VibrationEffect mEffectClick = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
+ private final VibrationEffect mEffectHeavy =
+ VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
+ private final VibrationEffect mDoubleClick =
+ VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
+
private final PowerManager mPowerManager;
private final VibrationEffect mSuccessVibrationEffect;
private final VibrationEffect mErrorVibrationEffect;
@@ -61,8 +72,8 @@
super(context, lazyDaemon, token, listener, userId, owner, cookie, sensorId, statsModality,
statsAction, statsClient);
mPowerManager = context.getSystemService(PowerManager.class);
- mSuccessVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
- mErrorVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
+ mSuccessVibrationEffect = mEffectClick;
+ mErrorVibrationEffect = mDoubleClick;
}
@Override
@@ -181,18 +192,47 @@
mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
}
+ protected @NonNull VibrationEffect getSuccessVibrationEffect() {
+ return mSuccessVibrationEffect;
+ }
+
+ protected @NonNull VibrationEffect getErrorVibrationEffect() {
+ return mErrorVibrationEffect;
+ }
protected final void vibrateSuccess() {
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
if (vibrator != null) {
- vibrator.vibrate(mSuccessVibrationEffect, VIBRATION_SONFICATION_ATTRIBUTES);
+ vibrator.vibrate(getSuccessVibrationEffect(), VIBRATION_SONFICATION_ATTRIBUTES);
}
}
protected final void vibrateError() {
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
if (vibrator != null) {
- vibrator.vibrate(mErrorVibrationEffect, VIBRATION_SONFICATION_ATTRIBUTES);
+ vibrator.vibrate(getErrorVibrationEffect(), VIBRATION_SONFICATION_ATTRIBUTES);
+ }
+ }
+
+ protected final @NonNull VibrationEffect getVibration(@Nullable String effect,
+ @NonNull VibrationEffect defaultEffect) {
+ if (TextUtils.isEmpty(effect)) {
+ return defaultEffect;
+ }
+
+ switch (effect.toLowerCase()) {
+ case "click":
+ return mEffectClick;
+ case "heavy":
+ return mEffectHeavy;
+ case "texture_tick":
+ return mEffectTextureTick;
+ case "tick":
+ return mEffectTick;
+ case "double_click":
+ return mDoubleClick;
+ default:
+ return defaultEffect;
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index cf545f3..8668828 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -22,6 +22,7 @@
import android.app.ActivityTaskManager;
import android.app.TaskStackListener;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -30,6 +31,8 @@
import android.hardware.biometrics.BiometricsProtoEnums;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.VibrationEffect;
+import android.provider.Settings;
import android.security.KeyStore;
import android.util.EventLog;
import android.util.Slog;
@@ -56,12 +59,14 @@
private final LockoutTracker mLockoutTracker;
private final boolean mIsRestricted;
private final boolean mAllowBackgroundAuthentication;
+ @NonNull private final ContentResolver mContentResolver;
protected final long mOperationId;
private long mStartTimeMs;
protected boolean mAuthAttempted;
+ private final boolean mCustomHaptics;
public AuthenticationClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
@@ -80,6 +85,10 @@
mLockoutTracker = lockoutTracker;
mIsRestricted = restricted;
mAllowBackgroundAuthentication = allowBackgroundAuthentication;
+
+ mContentResolver = context.getContentResolver();
+ mCustomHaptics = Settings.Global.getInt(mContentResolver,
+ "fp_custom_success_error", 0) == 1;
}
public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
@@ -333,4 +342,25 @@
public boolean interruptsPrecedingClients() {
return true;
}
+
+ @Override
+ protected @NonNull VibrationEffect getSuccessVibrationEffect() {
+ if (!mCustomHaptics) {
+ return super.getSuccessVibrationEffect();
+ }
+
+ return getVibration(Settings.Global.getString(mContentResolver,
+ "fp_success_type"), super.getSuccessVibrationEffect());
+ }
+
+ @Override
+ protected @NonNull VibrationEffect getErrorVibrationEffect() {
+ if (!mCustomHaptics) {
+ return super.getErrorVibrationEffect();
+ }
+
+ return getVibration(Settings.Global.getString(mContentResolver,
+ "fp_error_type"), super.getErrorVibrationEffect());
+
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index f8a2156..aa50790 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -471,7 +471,7 @@
* Adds a {@link BaseClientMonitor} to the pending queue
*
* @param clientMonitor operation to be scheduled
- * @param clientCallback optional callback, invoked when the client state changes
+ * @param clientCallback optional callback, invoked when the client state changes.
*/
public void scheduleClientMonitor(@NonNull BaseClientMonitor clientMonitor,
@Nullable BaseClientMonitor.Callback clientCallback) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceCallback.java b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceCallback.java
deleted file mode 100644
index 2ae6ccd..0000000
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceCallback.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.biometrics.sensors;
-
-/**
- * System_server services that require BiometricService to load before finishing initialization
- * should implement this interface.
- */
-public interface BiometricServiceCallback {
- /**
- * Notifies the service that BiometricService is initialized.
- */
- void onBiometricServiceReady();
-}
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
index 25b7add..d82847c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
@@ -146,9 +146,10 @@
}
}
- public void onFeatureGet(boolean success, int feature, boolean value) throws RemoteException {
+ public void onFeatureGet(boolean success, int[] features, boolean[] featureState)
+ throws RemoteException {
if (mFaceServiceReceiver != null) {
- mFaceServiceReceiver.onFeatureGet(success, feature, value);
+ mFaceServiceReceiver.onFeatureGet(success, features, featureState);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
index 0002ad2..0bc4f1b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
@@ -36,7 +36,7 @@
private final IFaceService mFaceService;
private final int mSensorId;
- public FaceAuthenticator(IFaceService faceService, int sensorId) throws RemoteException {
+ public FaceAuthenticator(IFaceService faceService, int sensorId) {
mFaceService = faceService;
mSensorId = sensorId;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index ada8476..94d47aa 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -57,7 +57,6 @@
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
-import com.android.server.biometrics.sensors.BiometricServiceCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -76,7 +75,7 @@
* The service is responsible for maintaining a list of clients and dispatching all
* face-related events.
*/
-public class FaceService extends SystemService implements BiometricServiceCallback {
+public class FaceService extends SystemService {
protected static final String TAG = "FaceService";
@@ -618,12 +617,76 @@
new ClientMonitorCallbackConverter(receiver), opPackageName);
}
+ private void addHidlProviders(@NonNull List<FaceSensorPropertiesInternal> hidlSensors) {
+ for (FaceSensorPropertiesInternal hidlSensor : hidlSensors) {
+ mServiceProviders.add(
+ new Face10(getContext(), hidlSensor, mLockoutResetDispatcher));
+ }
+ }
+
+ private void addAidlProviders() {
+ final String[] instances = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR);
+ if (instances == null || instances.length == 0) {
+ return;
+ }
+ for (String instance : instances) {
+ final String fqName = IFace.DESCRIPTOR + "/" + instance;
+ final IFace face = IFace.Stub.asInterface(
+ ServiceManager.waitForDeclaredService(fqName));
+ if (face == null) {
+ Slog.e(TAG, "Unable to get declared service: " + fqName);
+ continue;
+ }
+ try {
+ final SensorProps[] props = face.getSensorProps();
+ final FaceProvider provider = new FaceProvider(getContext(), props, instance,
+ mLockoutResetDispatcher);
+ mServiceProviders.add(provider);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
+ }
+ }
+ }
+
@Override // Binder call
- public void initializeConfiguration(int sensorId,
- @BiometricManager.Authenticators.Types int strength) {
+ public void registerAuthenticators(
+ @NonNull List<FaceSensorPropertiesInternal> hidlSensors) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- mServiceProviders.add(
- new Face10(getContext(), sensorId, strength, mLockoutResetDispatcher));
+
+ // Some HAL might not be started before the system service and will cause the code below
+ // to wait, and some of the operations below might take a significant amount of time to
+ // complete (calls to the HALs). To avoid blocking the rest of system server we put
+ // this on a background thread.
+ final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
+ true /* allowIo */);
+ thread.start();
+ final Handler handler = new Handler(thread.getLooper());
+
+ handler.post(() -> {
+ addHidlProviders(hidlSensors);
+ addAidlProviders();
+
+ final IBiometricService biometricService = IBiometricService.Stub.asInterface(
+ ServiceManager.getService(Context.BIOMETRIC_SERVICE));
+
+ // Register each sensor individually with BiometricService
+ for (ServiceProvider provider : mServiceProviders) {
+ final List<FaceSensorPropertiesInternal> props = provider.getSensorProperties();
+ for (FaceSensorPropertiesInternal prop : props) {
+ final int sensorId = prop.sensorId;
+ final @BiometricManager.Authenticators.Types int strength =
+ Utils.propertyStrengthToAuthenticatorStrength(prop.sensorStrength);
+ final FaceAuthenticator authenticator = new FaceAuthenticator(
+ mServiceWrapper, sensorId);
+ try {
+ biometricService.registerAuthenticator(sensorId, TYPE_FACE, strength,
+ authenticator);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId);
+ }
+ }
+ }
+ });
}
}
@@ -636,57 +699,6 @@
}
@Override
- public void onBiometricServiceReady() {
- final IBiometricService biometricService = IBiometricService.Stub.asInterface(
- ServiceManager.getService(Context.BIOMETRIC_SERVICE));
-
- final String[] instances = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR);
- if (instances == null || instances.length == 0) {
- return;
- }
-
- // If for some reason the HAL is not started before the system service, do not block
- // the rest of system server. Put this on a background thread.
- final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
- true /* allowIo */);
- thread.start();
- final Handler handler = new Handler(thread.getLooper());
-
- handler.post(() -> {
- for (String instance : instances) {
- final String fqName = IFace.DESCRIPTOR + "/" + instance;
- final IFace face = IFace.Stub.asInterface(
- ServiceManager.waitForDeclaredService(fqName));
- try {
- final SensorProps[] props = face.getSensorProps();
- final FaceProvider provider = new FaceProvider(getContext(), props, instance,
- mLockoutResetDispatcher);
- mServiceProviders.add(provider);
-
- // Register each sensor individually with BiometricService
- for (SensorProps prop : props) {
- final int sensorId = prop.commonProps.sensorId;
- @BiometricManager.Authenticators.Types int strength =
- Utils.propertyStrengthToAuthenticatorStrength(
- prop.commonProps.sensorStrength);
- final FaceAuthenticator authenticator =
- new FaceAuthenticator(mServiceWrapper, sensorId);
- try {
- biometricService.registerAuthenticator(sensorId, TYPE_FACE, strength,
- authenticator);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when registering sensorId: "
- + sensorId);
- }
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when initializing instance: " + fqName);
- }
- }
- });
- }
-
- @Override
public void onStart() {
publishBinderService(Context.FACE_SERVICE, mServiceWrapper);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java
index e444b33..5d713f3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java
@@ -31,7 +31,7 @@
import android.hardware.face.FaceEnrollFrame;
/**
- * Utilities for converting between hardware and framework-defined AIDL models.
+ * Utilities for converting from hardware to framework-defined AIDL models.
*/
final class AidlConversionUtils {
// Prevent instantiation.
@@ -128,17 +128,19 @@
}
@NonNull
- public static FaceAuthenticationFrame convert(@NonNull AuthenticationFrame frame) {
- return new FaceAuthenticationFrame(convert(frame.data));
+ public static FaceAuthenticationFrame toFrameworkAuthenticationFrame(
+ @NonNull AuthenticationFrame frame) {
+ return new FaceAuthenticationFrame(toFrameworkBaseFrame(frame.data));
}
@NonNull
- public static FaceEnrollFrame convert(@NonNull EnrollmentFrame frame) {
- return new FaceEnrollFrame(convert(frame.cell), frame.stage, convert(frame.data));
+ public static FaceEnrollFrame toFrameworkEnrollmentFrame(@NonNull EnrollmentFrame frame) {
+ return new FaceEnrollFrame(toFrameworkCell(frame.cell), frame.stage,
+ toFrameworkBaseFrame(frame.data));
}
@NonNull
- public static FaceDataFrame convert(@NonNull BaseFrame frame) {
+ public static FaceDataFrame toFrameworkBaseFrame(@NonNull BaseFrame frame) {
return new FaceDataFrame(
toFrameworkAcquiredInfo(frame.acquiredInfo),
frame.vendorCode,
@@ -149,7 +151,7 @@
}
@Nullable
- public static FaceEnrollCell convert(@Nullable Cell cell) {
+ public static FaceEnrollCell toFrameworkCell(@Nullable Cell cell) {
return cell == null ? null : new FaceEnrollCell(cell.x, cell.y, cell.z);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
index ca9be67..8726923 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
@@ -105,7 +105,7 @@
}
@Override
- public void onFeatureGet(boolean success, int feature, boolean value) {
+ public void onFeatureGet(boolean success, int[] features, boolean[] featureState) {
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index 0c883b0..d04c17c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.NotificationManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -32,6 +33,8 @@
import android.hardware.face.FaceManager;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.VibrationEffect;
+import android.provider.Settings;
import android.util.Slog;
import com.android.internal.R;
@@ -57,6 +60,9 @@
@Nullable private final NotificationManager mNotificationManager;
@Nullable private ICancellationSignal mCancellationSignal;
+ @NonNull private final ContentResolver mContentResolver;
+ private final boolean mCustomHaptics;
+
private final int[] mBiometricPromptIgnoreList;
private final int[] mBiometricPromptIgnoreListVendor;
private final int[] mKeyguardIgnoreList;
@@ -87,6 +93,10 @@
R.array.config_face_acquire_keyguard_ignorelist);
mKeyguardIgnoreListVendor = resources.getIntArray(
R.array.config_face_acquire_vendor_keyguard_ignorelist);
+
+ mContentResolver = context.getContentResolver();
+ mCustomHaptics = Settings.Global.getInt(mContentResolver,
+ "face_custom_success_error", 0) == 1;
}
@Override
@@ -243,4 +253,24 @@
Slog.e(TAG, "Remote exception", e);
}
}
+
+ @Override
+ protected @NonNull VibrationEffect getSuccessVibrationEffect() {
+ if (!mCustomHaptics) {
+ return super.getSuccessVibrationEffect();
+ }
+
+ return getVibration(Settings.Global.getString(mContentResolver,
+ "face_success_type"), super.getSuccessVibrationEffect());
+ }
+
+ @Override
+ protected @NonNull VibrationEffect getErrorVibrationEffect() {
+ if (!mCustomHaptics) {
+ return super.getErrorVibrationEffect();
+ }
+
+ return getVibration(Settings.Global.getString(mContentResolver,
+ "face_error_type"), super.getErrorVibrationEffect());
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClient.java
new file mode 100644
index 0000000..12f3e87
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClient.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.biometrics.BiometricFaceConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.Feature;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.util.Slog;
+
+import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.ErrorConsumer;
+import com.android.server.biometrics.sensors.HalClientMonitor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Face-specific get feature client for the {@link IFace} AIDL HAL interface.
+ */
+public class FaceGetFeatureClient extends HalClientMonitor<ISession> implements ErrorConsumer {
+
+ private static final String TAG = "FaceGetFeatureClient";
+
+ private final int mUserId;
+
+ FaceGetFeatureClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
+ @NonNull IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId,
+ @NonNull String owner, int sensorId) {
+ super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
+ BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
+ BiometricsProtoEnums.CLIENT_UNKNOWN);
+ mUserId = userId;
+ }
+
+ @Override
+ public void unableToStart() {
+ mCallback.onClientFinished(this, false /* success */);
+ }
+
+ @Override
+ public void start(@NonNull Callback callback) {
+ super.start(callback);
+ startHalOperation();
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ getFreshDaemon().getFeatures();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to getFeature", e);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_GET_FEATURE;
+ }
+
+ public void onFeatureGet(boolean success, byte[] features) {
+ HashMap<Integer, Boolean> featureMap = getFeatureMap();
+ int[] featuresToSend = new int[featureMap.size()];
+ boolean[] featureState = new boolean[featureMap.size()];
+
+ // The AIDL get feature api states that the presence of a feature means
+ // it is enabled, while the lack thereof means its disabled.
+ for (int i = 0; i < features.length; i++) {
+ Integer feature = convertAidlToFrameworkFeature(features[i]);
+ if (feature != null) {
+ featureMap.put(feature, true);
+ }
+ }
+
+ int i = 0;
+ for (Map.Entry<Integer, Boolean> entry : featureMap.entrySet()) {
+ featuresToSend[i] = entry.getKey();
+ featureState[i] = entry.getValue();
+ i++;
+ }
+
+ boolean attentionEnabled = featureMap.get(BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION);
+ Slog.d(TAG, "Updating attention value for user: " + mUserId
+ + " to value: " + attentionEnabled);
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED,
+ attentionEnabled ? 1 : 0, mUserId);
+ try {
+ getListener().onFeatureGet(success, featuresToSend, featureState);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+
+ mCallback.onClientFinished(this, true /* success */);
+ }
+
+ private @NonNull HashMap<Integer, Boolean> getFeatureMap() {
+ HashMap<Integer, Boolean> featureMap = new HashMap<>();
+ featureMap.put(BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION, false);
+ return featureMap;
+ }
+
+ private Integer convertAidlToFrameworkFeature(byte feature) {
+ switch (feature) {
+ case Feature.REQUIRE_ATTENTION:
+ return new Integer(BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION);
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public void onError(int errorCode, int vendorCode) {
+ try {
+ getListener().onFeatureGet(false /* success */, new int[0], new boolean[0]);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+
+ mCallback.onClientFinished(this, false /* success */);
+ }
+
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index b8bac40..23be50e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -435,13 +435,36 @@
public void scheduleSetFeature(int sensorId, @NonNull IBinder token, int userId, int feature,
boolean enabled, @NonNull byte[] hardwareAuthToken,
@NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
- // TODO(b/171335732): implement this.
+ mHandler.post(() -> {
+ final List<Face> faces = FaceUtils.getInstance(sensorId)
+ .getBiometricsForUser(mContext, userId);
+ if (faces.isEmpty()) {
+ Slog.w(getTag(), "Ignoring setFeature, no templates enrolled for user: " + userId);
+ return;
+ }
+ final FaceSetFeatureClient client = new FaceSetFeatureClient(mContext,
+ mSensors.get(sensorId).getLazySession(), token,
+ new ClientMonitorCallbackConverter(receiver), userId,
+ mContext.getOpPackageName(), sensorId, feature, enabled, hardwareAuthToken);
+ scheduleForSensor(sensorId, client);
+ });
}
@Override
public void scheduleGetFeature(int sensorId, @NonNull IBinder token, int userId, int feature,
@NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName) {
- // TODO(b/171335732): implement this.
+ mHandler.post(() -> {
+ final List<Face> faces = FaceUtils.getInstance(sensorId)
+ .getBiometricsForUser(mContext, userId);
+ if (faces.isEmpty()) {
+ Slog.w(getTag(), "Ignoring getFeature, no templates enrolled for user: " + userId);
+ return;
+ }
+ final FaceGetFeatureClient client = new FaceGetFeatureClient(mContext,
+ mSensors.get(sensorId).getLazySession(), token, callback, userId,
+ mContext.getOpPackageName(), sensorId);
+ scheduleForSensor(sensorId, client);
+ });
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClient.java
new file mode 100644
index 0000000..c3abfc2
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClient.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricFaceConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.Feature;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.keymaster.HardwareAuthToken;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.HardwareAuthTokenUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.ErrorConsumer;
+import com.android.server.biometrics.sensors.HalClientMonitor;
+
+/**
+ * Face-specific get feature client for the {@link IFace} AIDL HAL interface.
+ */
+public class FaceSetFeatureClient extends HalClientMonitor<ISession> implements ErrorConsumer {
+
+ private static final String TAG = "FaceSetFeatureClient";
+
+ private final int mFeature;
+ private final boolean mEnabled;
+ private final HardwareAuthToken mHardwareAuthToken;
+
+ FaceSetFeatureClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
+ @NonNull String owner, int sensorId, int feature, boolean enabled,
+ byte[] hardwareAuthToken) {
+ super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
+ BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
+ BiometricsProtoEnums.CLIENT_UNKNOWN);
+ mFeature = feature;
+ mEnabled = enabled;
+ mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
+ }
+
+ @Override
+ public void unableToStart() {
+ try {
+ getListener().onFeatureSet(false /* success */, mFeature);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to send error", e);
+ }
+ }
+
+ @Override
+ public void start(@NonNull Callback callback) {
+ super.start(callback);
+ startHalOperation();
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ getFreshDaemon()
+ .setFeature(mHardwareAuthToken,
+ convertFrameworkToAidlFeature(mFeature), mEnabled);
+ } catch (RemoteException | IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to set feature: " + mFeature + " to enabled: " + mEnabled, e);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_SET_FEATURE;
+ }
+
+ public void onFeatureSet(boolean success) {
+ try {
+ getListener().onFeatureSet(success, mFeature);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+
+ mCallback.onClientFinished(this, true /* success */);
+ }
+
+ private byte convertFrameworkToAidlFeature(int feature) throws IllegalArgumentException {
+ switch (feature) {
+ case BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION:
+ return Feature.REQUIRE_ATTENTION;
+ default:
+ Slog.e(TAG, "Unsupported feature : " + feature);
+ throw new IllegalArgumentException();
+ }
+ }
+
+ @Override
+ public void onError(int errorCode, int vendorCode) {
+ try {
+ getListener().onFeatureSet(false /* success */, mFeature);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+
+ mCallback.onClientFinished(this, false /* success */);
+ }
+
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index 4dcaf52..724531e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -186,7 +186,7 @@
return;
}
((FaceAuthenticationClient) client).onAuthenticationFrame(
- AidlConversionUtils.convert(frame));
+ AidlConversionUtils.toFrameworkAuthenticationFrame(frame));
});
}
@@ -204,7 +204,8 @@
+ Utils.getClientName(client));
return;
}
- ((FaceEnrollClient) client).onEnrollmentFrame(AidlConversionUtils.convert(frame));
+ ((FaceEnrollClient) client).onEnrollmentFrame(
+ AidlConversionUtils.toFrameworkEnrollmentFrame(frame));
});
}
@@ -376,12 +377,32 @@
@Override
public void onFeaturesRetrieved(byte[] features) {
+ mHandler.post(() -> {
+ final BaseClientMonitor client = mScheduler.getCurrentClient();
+ if (!(client instanceof FaceGetFeatureClient)) {
+ Slog.e(mTag, "onFeaturesRetrieved for non-get feature consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+ final FaceGetFeatureClient faceGetFeatureClient = (FaceGetFeatureClient) client;
+ faceGetFeatureClient.onFeatureGet(true /* success */, features);
+ });
}
@Override
public void onFeatureSet(byte feature) {
+ mHandler.post(() -> {
+ final BaseClientMonitor client = mScheduler.getCurrentClient();
+ if (!(client instanceof FaceSetFeatureClient)) {
+ Slog.e(mTag, "onFeatureSet for non-set consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+ final FaceSetFeatureClient faceSetFeatureClient = (FaceSetFeatureClient) client;
+ faceSetFeatureClient.onFeatureSet(true /* success */);
+ });
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
index e8668ed..f806767 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
@@ -94,7 +94,7 @@
}
@Override
- public void onFeatureGet(boolean success, int feature, boolean value) {
+ public void onFeatureGet(boolean success, int[] features, boolean[] featureState) {
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index a40155b..5dfc590 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -25,15 +25,12 @@
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricFaceConstants;
-import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricsProtoEnums;
-import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
import android.hardware.face.Face;
-import android.hardware.face.FaceSensorProperties;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
@@ -51,7 +48,6 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.biometrics.SensorServiceStateProto;
@@ -66,7 +62,6 @@
import com.android.server.biometrics.sensors.EnumerateConsumer;
import com.android.server.biometrics.sensors.ErrorConsumer;
import com.android.server.biometrics.sensors.HalClientMonitor;
-import com.android.server.biometrics.sensors.Interruptable;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.PerformanceTracker;
@@ -327,19 +322,13 @@
}
}
- @VisibleForTesting
- Face10(@NonNull Context context, int sensorId,
- @BiometricManager.Authenticators.Types int strength,
+ @VisibleForTesting Face10(@NonNull Context context,
+ @NonNull FaceSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
- boolean supportsSelfIllumination, int maxTemplatesAllowed,
@NonNull BiometricScheduler scheduler) {
- mSensorProperties = new FaceSensorPropertiesInternal(sensorId,
- Utils.authenticatorStrengthToPropertyStrength(strength),
- maxTemplatesAllowed, new ArrayList<ComponentInfoInternal>() /* componentInfo */,
- FaceSensorProperties.TYPE_UNKNOWN, false /* supportsFaceDetect */,
- supportsSelfIllumination, true /* resetLockoutRequiresChallenge */);
+ mSensorProperties = sensorProps;
mContext = context;
- mSensorId = sensorId;
+ mSensorId = sensorProps.sensorId;
mScheduler = scheduler;
mHandler = new Handler(Looper.getMainLooper());
mUsageStats = new UsageStats(context);
@@ -347,8 +336,8 @@
mLazyDaemon = Face10.this::getDaemon;
mLockoutTracker = new LockoutHalImpl();
mLockoutResetDispatcher = lockoutResetDispatcher;
- mHalResultController = new HalResultController(sensorId, context, mHandler, mScheduler,
- mLockoutTracker, lockoutResetDispatcher);
+ mHalResultController = new HalResultController(sensorProps.sensorId, context, mHandler,
+ mScheduler, mLockoutTracker, lockoutResetDispatcher);
mHalResultController.setCallback(() -> {
mDaemon = null;
mCurrentUserId = UserHandle.USER_NULL;
@@ -361,12 +350,9 @@
}
}
- public Face10(@NonNull Context context, int sensorId,
- @BiometricManager.Authenticators.Types int strength,
+ public Face10(@NonNull Context context, @NonNull FaceSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
- this(context, sensorId, strength, lockoutResetDispatcher,
- context.getResources().getBoolean(R.bool.config_faceAuthSupportsSelfIllumination),
- context.getResources().getInteger(R.integer.config_faceMaxTemplatesPerUser),
+ this(context, sensorProps, lockoutResetDispatcher,
new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */));
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index ff06a4a..c4bdb32 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -17,6 +17,7 @@
package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -27,6 +28,8 @@
import android.hardware.face.FaceManager;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.VibrationEffect;
+import android.provider.Settings;
import android.util.Slog;
import com.android.internal.R;
@@ -47,7 +50,8 @@
private static final String TAG = "FaceAuthenticationClient";
-
+ @NonNull private final ContentResolver mContentResolver;
+ private final boolean mCustomHaptics;
private final UsageStats mUsageStats;
private final int[] mBiometricPromptIgnoreList;
@@ -78,6 +82,10 @@
R.array.config_face_acquire_keyguard_ignorelist);
mKeyguardIgnoreListVendor = resources.getIntArray(
R.array.config_face_acquire_vendor_keyguard_ignorelist);
+
+ mContentResolver = context.getContentResolver();
+ mCustomHaptics = Settings.Global.getInt(mContentResolver,
+ "face_custom_success_error", 0) == 1;
}
@Override
@@ -188,4 +196,24 @@
final boolean shouldSend = shouldSend(acquireInfo, vendorCode);
onAcquiredInternal(acquireInfo, vendorCode, shouldSend);
}
+
+ @Override
+ protected @NonNull VibrationEffect getSuccessVibrationEffect() {
+ if (!mCustomHaptics) {
+ return super.getSuccessVibrationEffect();
+ }
+
+ return getVibration(Settings.Global.getString(mContentResolver,
+ "face_success_type"), super.getSuccessVibrationEffect());
+ }
+
+ @Override
+ protected @NonNull VibrationEffect getErrorVibrationEffect() {
+ if (!mCustomHaptics) {
+ return super.getErrorVibrationEffect();
+ }
+
+ return getVibration(Settings.Global.getString(mContentResolver,
+ "face_error_type"), super.getErrorVibrationEffect());
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
index b1083d4..7821601 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
@@ -58,7 +58,7 @@
public void unableToStart() {
try {
if (getListener() != null) {
- getListener().onFeatureGet(false /* success */, mFeature, false /* value */);
+ getListener().onFeatureGet(false /* success */, new int[0], new boolean[0]);
}
} catch (RemoteException e) {
Slog.e(TAG, "Unable to send error", e);
@@ -75,9 +75,14 @@
protected void startHalOperation() {
try {
final OptionalBool result = getFreshDaemon().getFeature(mFeature, mFaceId);
+ int[] features = new int[1];
+ boolean[] featureState = new boolean[1];
+ features[0] = mFeature;
+ featureState[0] = result.value;
mValue = result.value;
+
if (getListener() != null) {
- getListener().onFeatureGet(result.status == Status.OK, mFeature, mValue);
+ getListener().onFeatureGet(result.status == Status.OK, features, featureState);
}
mCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
index 8109680..1e59429 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
@@ -36,8 +36,7 @@
private final IFingerprintService mFingerprintService;
private final int mSensorId;
- public FingerprintAuthenticator(IFingerprintService fingerprintService, int sensorId)
- throws RemoteException {
+ public FingerprintAuthenticator(IFingerprintService fingerprintService, int sensorId) {
mFingerprintService = fingerprintService;
mSensorId = sensorId;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index deb251b..39b7a74 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -29,11 +29,6 @@
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_USER_CANCELED;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_VENDOR;
import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
-import static android.hardware.fingerprint.FingerprintStateListener.STATE_AUTH_OTHER;
-import static android.hardware.fingerprint.FingerprintStateListener.STATE_BP_AUTH;
-import static android.hardware.fingerprint.FingerprintStateListener.STATE_ENROLLING;
-import static android.hardware.fingerprint.FingerprintStateListener.STATE_IDLE;
-import static android.hardware.fingerprint.FingerprintStateListener.STATE_KEYGUARD_AUTH;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -55,7 +50,7 @@
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintServiceReceiver;
-import android.hardware.fingerprint.FingerprintStateListener;
+import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -67,6 +62,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -77,21 +73,18 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
-import com.android.server.biometrics.sensors.AuthenticationClient;
-import com.android.server.biometrics.sensors.BaseClientMonitor;
-import com.android.server.biometrics.sensors.BiometricServiceCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.fingerprint.aidl.FingerprintProvider;
import com.android.server.biometrics.sensors.fingerprint.hidl.Fingerprint21;
import com.android.server.biometrics.sensors.fingerprint.hidl.Fingerprint21UdfpsMock;
-import com.android.server.biometrics.sensors.fingerprint.hidl.FingerprintEnrollClient;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -105,71 +98,32 @@
* The service is responsible for maintaining a list of clients and dispatching all
* fingerprint-related events.
*/
-public class FingerprintService extends SystemService implements BiometricServiceCallback {
+public class FingerprintService extends SystemService {
protected static final String TAG = "FingerprintService";
+ private final Object mLock = new Object();
private final AppOpsManager mAppOps;
private final LockoutResetDispatcher mLockoutResetDispatcher;
private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
private final LockPatternUtils mLockPatternUtils;
private final FingerprintServiceWrapper mServiceWrapper;
- @NonNull private List<ServiceProvider> mServiceProviders;
+ @NonNull private final List<ServiceProvider> mServiceProviders;
@NonNull private final FingerprintStateCallback mFingerprintStateCallback;
- @NonNull private @FingerprintStateListener.State int mFingerprintState;
- private List<IFingerprintStateListener> mFingerprintStateListeners = new ArrayList<>();
+ @GuardedBy("mLock")
+ @NonNull private final RemoteCallbackList<IFingerprintAuthenticatorsRegisteredCallback>
+ mAuthenticatorsRegisteredCallbacks;
- /** Callback to receive notifications about changes in fingerprint state. */
- public final class FingerprintStateCallback implements BaseClientMonitor.Callback {
- @Override
- public void onClientStarted(@NonNull BaseClientMonitor client) {
- final int previousFingerprintState = mFingerprintState;
- if (client instanceof AuthenticationClient) {
- AuthenticationClient authClient = (AuthenticationClient) client;
- if (authClient.isKeyguard()) {
- mFingerprintState = STATE_KEYGUARD_AUTH;
- } else if (authClient.isBiometricPrompt()) {
- mFingerprintState = STATE_BP_AUTH;
- } else {
- mFingerprintState = STATE_AUTH_OTHER;
- }
- } else if (client instanceof FingerprintEnrollClient) {
- mFingerprintState = STATE_ENROLLING;
- } else {
- Slog.w(TAG, "Other authentication client: " + Utils.getClientName(client));
- mFingerprintState = STATE_IDLE;
- }
- Slog.d(TAG, "Fps state updated from " + previousFingerprintState + " to "
- + mFingerprintState + ", client " + client);
- notifyFingerprintStateListeners(mFingerprintState);
- }
-
- @Override
- public void onClientFinished(@NonNull BaseClientMonitor client, boolean success) {
- mFingerprintState = STATE_IDLE;
- Slog.d(TAG, "Client finished, fps state updated to " + mFingerprintState
- + ", client " + client);
- notifyFingerprintStateListeners(mFingerprintState);
- }
-
- private void notifyFingerprintStateListeners(@FingerprintStateListener.State int newState) {
- for (IFingerprintStateListener listener : mFingerprintStateListeners) {
- try {
- listener.onStateChanged(newState);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception in fingerprint state change", e);
- }
- }
- }
- }
+ @GuardedBy("mLock")
+ @NonNull private final List<FingerprintSensorPropertiesInternal> mSensorProps;
/**
* Registers FingerprintStateListener in list stored by FingerprintService
* @param listener new FingerprintStateListener being added
*/
- public void registerFingerprintStateListener(IFingerprintStateListener listener) {
- mFingerprintStateListeners.add(listener);
+ public void registerFingerprintStateListener(@NonNull IFingerprintStateListener listener) {
+ mFingerprintStateCallback.registerFingerprintStateListener(listener);
}
/**
@@ -636,7 +590,8 @@
: provider.getSensorProperties()) {
pw.println("Dumping for sensorId: " + props.sensorId
+ ", provider: " + provider.getClass().getSimpleName());
- pw.println("Fps state: " + mFingerprintState);
+ pw.println("Fps state: "
+ + mFingerprintStateCallback.getFingerprintState());
provider.dumpInternal(props.sensorId, pw);
pw.println();
}
@@ -800,7 +755,7 @@
@Override // Binder call
public void resetLockout(IBinder token, int sensorId, int userId,
- @Nullable byte [] hardwareAuthToken, String opPackageName) {
+ @Nullable byte[] hardwareAuthToken, String opPackageName) {
Utils.checkPermission(getContext(), RESET_FINGERPRINT_LOCKOUT);
final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -830,24 +785,119 @@
mGestureAvailabilityDispatcher.removeCallback(callback);
}
+ private void addHidlProviders(List<FingerprintSensorPropertiesInternal> hidlSensors) {
+ for (FingerprintSensorPropertiesInternal hidlSensor : hidlSensors) {
+ final Fingerprint21 fingerprint21;
+ if ((Build.IS_USERDEBUG || Build.IS_ENG)
+ && getContext().getResources().getBoolean(R.bool.allow_test_udfps)
+ && Settings.Secure.getIntForUser(getContext().getContentResolver(),
+ Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
+ UserHandle.USER_CURRENT) != 0) {
+ fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), hidlSensor,
+ mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
+ } else {
+ fingerprint21 = Fingerprint21.newInstance(getContext(), hidlSensor,
+ mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
+ }
+ mServiceProviders.add(fingerprint21);
+ }
+ }
+
+ private void addAidlProviders() {
+ final String[] instances = ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR);
+ if (instances == null || instances.length == 0) {
+ return;
+ }
+ for (String instance : instances) {
+ final String fqName = IFingerprint.DESCRIPTOR + "/" + instance;
+ final IFingerprint fp = IFingerprint.Stub.asInterface(
+ ServiceManager.waitForDeclaredService(fqName));
+ if (fp == null) {
+ Slog.e(TAG, "Unable to get declared service: " + fqName);
+ continue;
+ }
+ try {
+ final SensorProps[] props = fp.getSensorProps();
+ final FingerprintProvider provider =
+ new FingerprintProvider(getContext(), props, instance,
+ mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
+ mServiceProviders.add(provider);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
+ }
+ }
+ }
+
@Override // Binder call
- public void initializeConfiguration(int sensorId,
- @BiometricManager.Authenticators.Types int strength) {
+ public void registerAuthenticators(
+ @NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Fingerprint21 fingerprint21;
- if ((Build.IS_USERDEBUG || Build.IS_ENG)
- && getContext().getResources().getBoolean(R.bool.allow_test_udfps)
- && Settings.Secure.getIntForUser(getContext().getContentResolver(),
- Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
- UserHandle.USER_CURRENT) != 0) {
- fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), sensorId,
- strength, mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
- } else {
- fingerprint21 = Fingerprint21.newInstance(getContext(), sensorId, strength,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
+ // Some HAL might not be started before the system service and will cause the code below
+ // to wait, and some of the operations below might take a significant amount of time to
+ // complete (calls to the HALs). To avoid blocking the rest of system server we put
+ // this on a background thread.
+ final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
+ true /* allowIo */);
+ thread.start();
+ final Handler handler = new Handler(thread.getLooper());
+
+ handler.post(() -> {
+ addHidlProviders(hidlSensors);
+ addAidlProviders();
+
+ final IBiometricService biometricService = IBiometricService.Stub.asInterface(
+ ServiceManager.getService(Context.BIOMETRIC_SERVICE));
+
+ // Register each sensor individually with BiometricService
+ for (ServiceProvider provider : mServiceProviders) {
+ final List<FingerprintSensorPropertiesInternal> props =
+ provider.getSensorProperties();
+ for (FingerprintSensorPropertiesInternal prop : props) {
+ final int sensorId = prop.sensorId;
+ final @BiometricManager.Authenticators.Types int strength =
+ Utils.propertyStrengthToAuthenticatorStrength(prop.sensorStrength);
+ final FingerprintAuthenticator authenticator = new FingerprintAuthenticator(
+ mServiceWrapper, sensorId);
+ try {
+ biometricService.registerAuthenticator(sensorId, TYPE_FINGERPRINT,
+ strength, authenticator);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId);
+ }
+ }
+ }
+
+ synchronized (mLock) {
+ for (ServiceProvider provider : mServiceProviders) {
+ mSensorProps.addAll(provider.getSensorProperties());
+ }
+ }
+
+ broadcastAllAuthenticatorsRegistered();
+ });
+ }
+
+ @Override
+ public void addAuthenticatorsRegisteredCallback(
+ IFingerprintAuthenticatorsRegisteredCallback callback) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ if (callback == null) {
+ Slog.e(TAG, "addAuthenticatorsRegisteredCallback, callback is null");
+ return;
}
- mServiceProviders.add(fingerprint21);
+
+ final boolean registered;
+ final boolean hasSensorProps;
+ synchronized (mLock) {
+ registered = mAuthenticatorsRegisteredCallbacks.register(callback);
+ hasSensorProps = !mSensorProps.isEmpty();
+ }
+ if (registered && hasSensorProps) {
+ broadcastAllAuthenticatorsRegistered();
+ } else if (!registered) {
+ Slog.e(TAG, "addAuthenticatorsRegisteredCallback failed to register callback");
+ }
}
@Override
@@ -898,59 +948,40 @@
mLockPatternUtils = new LockPatternUtils(context);
mServiceProviders = new ArrayList<>();
mFingerprintStateCallback = new FingerprintStateCallback();
- mFingerprintState = STATE_IDLE;
+ mAuthenticatorsRegisteredCallbacks = new RemoteCallbackList<>();
+ mSensorProps = new ArrayList<>();
}
- @Override
- public void onBiometricServiceReady() {
- final IBiometricService biometricService = IBiometricService.Stub.asInterface(
- ServiceManager.getService(Context.BIOMETRIC_SERVICE));
-
- final String[] instances = ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR);
- if (instances == null || instances.length == 0) {
- return;
- }
-
- // If for some reason the HAL is not started before the system service, do not block
- // the rest of system server. Put this on a background thread.
- final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
- true /* allowIo */);
- thread.start();
- final Handler handler = new Handler(thread.getLooper());
-
- handler.post(() -> {
- for (String instance : instances) {
- final String fqName = IFingerprint.DESCRIPTOR + "/" + instance;
- final IFingerprint fp = IFingerprint.Stub.asInterface(
- ServiceManager.waitForDeclaredService(fqName));
- try {
- final SensorProps[] props = fp.getSensorProps();
- final FingerprintProvider provider =
- new FingerprintProvider(getContext(), props, instance,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
- mServiceProviders.add(provider);
-
- // Register each sensor individually with BiometricService
- for (SensorProps prop : props) {
- final int sensorId = prop.commonProps.sensorId;
- @BiometricManager.Authenticators.Types int strength =
- Utils.propertyStrengthToAuthenticatorStrength(
- prop.commonProps.sensorStrength);
- final FingerprintAuthenticator authenticator =
- new FingerprintAuthenticator(mServiceWrapper, sensorId);
- try {
- biometricService.registerAuthenticator(sensorId,
- TYPE_FINGERPRINT, strength, authenticator);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when registering sensorId: "
- + sensorId);
- }
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when initializing instance: " + fqName);
- }
+ // Notifies the callbacks that all of the authenticators have been registered and removes the
+ // invoked callbacks from the callback list.
+ private void broadcastAllAuthenticatorsRegistered() {
+ // Make a local copy of the data so it can be used outside of the synchronized block when
+ // making Binder calls.
+ final List<IFingerprintAuthenticatorsRegisteredCallback> callbacks = new ArrayList<>();
+ final List<FingerprintSensorPropertiesInternal> props;
+ synchronized (mLock) {
+ if (!mSensorProps.isEmpty()) {
+ props = new ArrayList<>(mSensorProps);
+ } else {
+ Slog.e(TAG, "mSensorProps is empty");
+ return;
}
- });
+ final int n = mAuthenticatorsRegisteredCallbacks.beginBroadcast();
+ for (int i = 0; i < n; ++i) {
+ final IFingerprintAuthenticatorsRegisteredCallback cb =
+ mAuthenticatorsRegisteredCallbacks.getBroadcastItem(i);
+ callbacks.add(cb);
+ mAuthenticatorsRegisteredCallbacks.unregister(cb);
+ }
+ mAuthenticatorsRegisteredCallbacks.finishBroadcast();
+ }
+ for (IFingerprintAuthenticatorsRegisteredCallback cb : callbacks) {
+ try {
+ cb.onAllAuthenticatorsRegistered(props);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in onAllAuthenticatorsRegistered", e);
+ }
+ }
}
@Override
@@ -995,12 +1026,9 @@
@NonNull
private List<FingerprintSensorPropertiesInternal> getSensorProperties() {
- final List<FingerprintSensorPropertiesInternal> properties = new ArrayList<>();
-
- for (ServiceProvider provider : mServiceProviders) {
- properties.addAll(provider.getSensorProperties());
+ synchronized (mLock) {
+ return mSensorProps;
}
- return properties;
}
@NonNull
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java
new file mode 100644
index 0000000..5f998d8
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors.fingerprint;
+
+import static android.hardware.fingerprint.FingerprintStateListener.STATE_AUTH_OTHER;
+import static android.hardware.fingerprint.FingerprintStateListener.STATE_BP_AUTH;
+import static android.hardware.fingerprint.FingerprintStateListener.STATE_ENROLLING;
+import static android.hardware.fingerprint.FingerprintStateListener.STATE_IDLE;
+import static android.hardware.fingerprint.FingerprintStateListener.STATE_KEYGUARD_AUTH;
+
+import android.annotation.NonNull;
+import android.hardware.fingerprint.FingerprintStateListener;
+import android.hardware.fingerprint.IFingerprintStateListener;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.fingerprint.hidl.FingerprintEnrollClient;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * A callback for receiving notifications about changes in fingerprint state.
+ */
+public class FingerprintStateCallback implements BaseClientMonitor.Callback {
+ private @FingerprintStateListener.State int mFingerprintState;
+ @NonNull private final CopyOnWriteArrayList<IFingerprintStateListener>
+ mFingerprintStateListeners = new CopyOnWriteArrayList<>();
+
+ public FingerprintStateCallback() {
+ mFingerprintState = STATE_IDLE;
+ }
+
+ public int getFingerprintState() {
+ return mFingerprintState;
+ }
+
+ @Override
+ public void onClientStarted(@NonNull BaseClientMonitor client) {
+ final int previousFingerprintState = mFingerprintState;
+ if (client instanceof AuthenticationClient) {
+ AuthenticationClient authClient = (AuthenticationClient) client;
+ if (authClient.isKeyguard()) {
+ mFingerprintState = STATE_KEYGUARD_AUTH;
+ } else if (authClient.isBiometricPrompt()) {
+ mFingerprintState = STATE_BP_AUTH;
+ } else {
+ mFingerprintState = STATE_AUTH_OTHER;
+ }
+ } else if (client instanceof FingerprintEnrollClient) {
+ mFingerprintState = STATE_ENROLLING;
+ } else {
+ Slog.w(FingerprintService.TAG,
+ "Other authentication client: " + Utils.getClientName(client));
+ mFingerprintState = STATE_IDLE;
+ }
+ Slog.d(FingerprintService.TAG, "Fps state updated from " + previousFingerprintState
+ + " to " + mFingerprintState + ", client " + client);
+ notifyFingerprintStateListeners(mFingerprintState);
+ }
+
+ @Override
+ public void onClientFinished(@NonNull BaseClientMonitor client, boolean success) {
+ mFingerprintState = STATE_IDLE;
+ Slog.d(FingerprintService.TAG,
+ "Client finished, fps state updated to " + mFingerprintState + ", client "
+ + client);
+ notifyFingerprintStateListeners(mFingerprintState);
+ }
+
+ private void notifyFingerprintStateListeners(@FingerprintStateListener.State int newState) {
+ for (IFingerprintStateListener listener : mFingerprintStateListeners) {
+ try {
+ listener.onStateChanged(newState);
+ } catch (RemoteException e) {
+ Slog.e(FingerprintService.TAG, "Remote exception in fingerprint state change", e);
+ }
+ }
+ }
+
+ /**
+ * Enables clients to register a FingerprintStateListener. Used by FingerprintService to forward
+ * updates in fingerprint sensor state to the SideFpNsEventHandler
+ * @param listener
+ */
+ public void registerFingerprintStateListener(@NonNull IFingerprintStateListener listener) {
+ mFingerprintStateListeners.add(listener);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index e610448..701b9a7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -87,20 +87,20 @@
void scheduleEnroll(int sensorId, @NonNull IBinder token, byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
@FingerprintManager.EnrollReason int enrollReason,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback);
+ @NonNull FingerprintStateCallback fingerprintStateCallback);
void cancelEnrollment(int sensorId, @NonNull IBinder token);
void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
int statsClient,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback);
+ @NonNull FingerprintStateCallback fingerprintStateCallback);
void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback);
+ @NonNull FingerprintStateCallback fingerprintStateCallback);
void startPreparedClient(int sensorId, int cookie);
@@ -151,6 +151,6 @@
@NonNull
ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback,
+ @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull String opPackageName);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java
index 07637fe..66142bf 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java
@@ -21,7 +21,7 @@
import android.hardware.biometrics.fingerprint.Error;
/**
- * Utilities for converting between hardware and framework-defined AIDL models.
+ * Utilities for converting from hardware to framework-defined AIDL models.
*/
final class AidlConversionUtils {
// Prevent instantiation.
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
index 66bd73c..e34afc0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
@@ -32,7 +32,7 @@
import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.BaseClientMonitor;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintService;
+import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import java.util.HashSet;
@@ -51,7 +51,7 @@
@NonNull private final Context mContext;
private final int mSensorId;
@NonNull private final ITestSessionCallback mCallback;
- @NonNull private final FingerprintService.FingerprintStateCallback mFingerprintStateCallback;
+ @NonNull private final FingerprintStateCallback mFingerprintStateCallback;
@NonNull private final FingerprintProvider mProvider;
@NonNull private final Sensor mSensor;
@NonNull private final Set<Integer> mEnrollmentIds;
@@ -117,7 +117,7 @@
BiometricTestSessionImpl(@NonNull Context context, int sensorId,
@NonNull ITestSessionCallback callback,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback,
+ @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintProvider provider,
@NonNull Sensor sensor) {
mContext = context;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index f1e37e0..c23c113 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -55,7 +55,7 @@
import com.android.server.biometrics.sensors.InvalidationRequesterClient;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.PerformanceTracker;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintService;
+import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import com.android.server.biometrics.sensors.fingerprint.ServiceProvider;
@@ -320,7 +320,7 @@
public void scheduleEnroll(int sensorId, @NonNull IBinder token, byte[] hardwareAuthToken,
int userId, @NonNull IFingerprintServiceReceiver receiver,
@NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback) {
+ @NonNull FingerprintStateCallback fingerprintStateCallback) {
mHandler.post(() -> {
final int maxTemplatesPerUser = mSensors.get(sensorId).getSensorProperties()
.maxEnrollmentsPerUser;
@@ -358,7 +358,7 @@
public void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
int statsClient,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback) {
+ @NonNull FingerprintStateCallback fingerprintStateCallback) {
mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FingerprintDetectClient client = new FingerprintDetectClient(mContext,
@@ -374,7 +374,7 @@
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback) {
+ @NonNull FingerprintStateCallback fingerprintStateCallback) {
mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient(
@@ -572,7 +572,7 @@
@NonNull
@Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback,
+ @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull String opPackageName) {
return mSensors.get(sensorId).createTestSession(callback, fingerprintStateCallback);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index 1c016f6..cf915ad 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -58,7 +58,7 @@
import com.android.server.biometrics.sensors.StartUserClient;
import com.android.server.biometrics.sensors.StopUserClient;
import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintService;
+import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
@@ -488,7 +488,7 @@
}
@NonNull ITestSession createTestSession(@NonNull ITestSessionCallback callback,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback) {
+ @NonNull FingerprintStateCallback fingerprintStateCallback) {
return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, callback,
fingerprintStateCallback, mProvider, this);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
index 4ff6a8f..ad4f679 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
@@ -31,7 +31,7 @@
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.BaseClientMonitor;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintService;
+import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import java.util.ArrayList;
@@ -52,7 +52,7 @@
@NonNull private final Context mContext;
private final int mSensorId;
@NonNull private final ITestSessionCallback mCallback;
- @NonNull private final FingerprintService.FingerprintStateCallback mFingerprintStateCallback;
+ @NonNull private final FingerprintStateCallback mFingerprintStateCallback;
@NonNull private final Fingerprint21 mFingerprint21;
@NonNull private final Fingerprint21.HalResultController mHalResultController;
@NonNull private final Set<Integer> mEnrollmentIds;
@@ -118,7 +118,7 @@
BiometricTestSessionImpl(@NonNull Context context, int sensorId,
@NonNull ITestSessionCallback callback,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback,
+ @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull Fingerprint21 fingerprint21,
@NonNull Fingerprint21.HalResultController halResultController) {
mContext = context;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index ed681c9..3528690 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -26,9 +26,7 @@
import android.content.Context;
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricConstants;
-import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricsProtoEnums;
-import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
@@ -50,9 +48,7 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.biometrics.SensorServiceStateProto;
import com.android.server.biometrics.SensorStateProto;
@@ -74,7 +70,7 @@
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.RemovalConsumer;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintService;
+import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import com.android.server.biometrics.sensors.fingerprint.ServiceProvider;
@@ -314,17 +310,22 @@
}
}
- Fingerprint21(@NonNull Context context, @NonNull BiometricScheduler scheduler,
- @NonNull Handler handler, int sensorId,
- @BiometricManager.Authenticators.Types int strength,
+ Fingerprint21(@NonNull Context context,
+ @NonNull FingerprintSensorPropertiesInternal sensorProps,
+ @NonNull BiometricScheduler scheduler, @NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull HalResultController controller) {
mContext = context;
- mSensorId = sensorId;
+
+ mSensorProperties = sensorProps;
+ mSensorId = sensorProps.sensorId;
+ mIsUdfps = sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
+ || sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC;
+ mIsPowerbuttonFps = sensorProps.sensorType == FingerprintSensorProperties.TYPE_POWER_BUTTON;
+
mScheduler = scheduler;
mHandler = handler;
mActivityTaskManager = ActivityTaskManager.getInstance();
-
mTaskStackListener = new BiometricTaskStackListener();
mAuthenticatorIds = Collections.synchronizedMap(new HashMap<>());
mLazyDaemon = Fingerprint21.this::getDaemon;
@@ -341,46 +342,20 @@
} catch (RemoteException e) {
Slog.e(TAG, "Unable to register user switch observer");
}
-
- // TODO(b/179175438): Remove this code block after transition to AIDL.
- // The existence of config_udfps_sensor_props indicates that the sensor is UDFPS.
- mIsUdfps = !ArrayUtils.isEmpty(
- mContext.getResources().getIntArray(R.array.config_udfps_sensor_props));
-
- // config_is_powerbutton_fps indicates whether device has a power button fingerprint sensor.
- mIsPowerbuttonFps = mContext.getResources().getBoolean(R.bool.config_is_powerbutton_fps);
-
- final @FingerprintSensorProperties.SensorType int sensorType;
- if (mIsUdfps) {
- sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
- } else if (mIsPowerbuttonFps) {
- sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON;
- } else {
- sensorType = FingerprintSensorProperties.TYPE_REAR;
- }
-
- // IBiometricsFingerprint@2.1 does not manage timeout below the HAL, so the Gatekeeper HAT
- // cannot be checked
- final boolean resetLockoutRequiresHardwareAuthToken = false;
- final int maxEnrollmentsPerUser = mContext.getResources()
- .getInteger(R.integer.config_fingerprintMaxTemplatesPerUser);
-
- mSensorProperties = new FingerprintSensorPropertiesInternal(context, sensorId,
- Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
- new ArrayList<ComponentInfoInternal>() /* componentInfo */, sensorType,
- resetLockoutRequiresHardwareAuthToken);
}
- public static Fingerprint21 newInstance(@NonNull Context context, int sensorId, int strength,
+ public static Fingerprint21 newInstance(@NonNull Context context,
+ @NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
final Handler handler = new Handler(Looper.getMainLooper());
final BiometricScheduler scheduler =
new BiometricScheduler(TAG, gestureAvailabilityDispatcher);
- final HalResultController controller = new HalResultController(sensorId, context, handler,
+ final HalResultController controller = new HalResultController(sensorProps.sensorId,
+ context, handler,
scheduler);
- return new Fingerprint21(context, scheduler, handler, sensorId, strength,
- lockoutResetDispatcher, controller);
+ return new Fingerprint21(context, sensorProps, scheduler, handler, lockoutResetDispatcher,
+ controller);
}
@Override
@@ -574,7 +549,7 @@
@NonNull byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
@FingerprintManager.EnrollReason int enrollReason,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback) {
+ @NonNull FingerprintStateCallback fingerprintStateCallback) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
@@ -614,7 +589,7 @@
public void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName,
int statsClient,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback) {
+ @NonNull FingerprintStateCallback fingerprintStateCallback) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
@@ -632,7 +607,7 @@
int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback) {
+ @NonNull FingerprintStateCallback fingerprintStateCallback) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
@@ -896,7 +871,7 @@
@NonNull
@Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
- @NonNull FingerprintService.FingerprintStateCallback fingerprintStateCallback,
+ @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull String opPackageName) {
return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, callback,
fingerprintStateCallback, this, mHalResultController);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index 48419c3..d1020a6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -21,8 +21,6 @@
import android.app.trust.TrustManager;
import android.content.ContentResolver;
import android.content.Context;
-import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
@@ -39,7 +37,6 @@
import android.util.SparseBooleanArray;
import com.android.internal.R;
-import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
@@ -271,8 +268,8 @@
}
}
- public static Fingerprint21UdfpsMock newInstance(@NonNull Context context, int sensorId,
- @BiometricManager.Authenticators.Types int strength,
+ public static Fingerprint21UdfpsMock newInstance(@NonNull Context context,
+ @NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
Slog.d(TAG, "Creating Fingerprint23Mock!");
@@ -281,8 +278,8 @@
final TestableBiometricScheduler scheduler =
new TestableBiometricScheduler(TAG, gestureAvailabilityDispatcher);
final MockHalResultController controller =
- new MockHalResultController(sensorId, context, handler, scheduler);
- return new Fingerprint21UdfpsMock(context, scheduler, handler, sensorId, strength,
+ new MockHalResultController(sensorProps.sensorId, context, handler, scheduler);
+ return new Fingerprint21UdfpsMock(context, sensorProps, scheduler, handler,
lockoutResetDispatcher, controller);
}
@@ -407,12 +404,12 @@
}
private Fingerprint21UdfpsMock(@NonNull Context context,
+ @NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull TestableBiometricScheduler scheduler,
- @NonNull Handler handler, int sensorId,
- @BiometricManager.Authenticators.Types int strength,
+ @NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull MockHalResultController controller) {
- super(context, scheduler, handler, sensorId, strength, lockoutResetDispatcher, controller);
+ super(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller);
mScheduler = scheduler;
mScheduler.init(this);
mHandler = handler;
@@ -420,11 +417,11 @@
final boolean resetLockoutRequiresHardwareAuthToken = false;
final int maxTemplatesAllowed = mContext.getResources()
.getInteger(R.integer.config_fingerprintMaxTemplatesPerUser);
- mSensorProperties = new FingerprintSensorPropertiesInternal(sensorId,
- Utils.authenticatorStrengthToPropertyStrength(strength), maxTemplatesAllowed,
- new ArrayList<ComponentInfoInternal>() /* componentInfo */,
+ mSensorProperties = new FingerprintSensorPropertiesInternal(sensorProps.sensorId,
+ sensorProps.sensorStrength, maxTemplatesAllowed, sensorProps.componentInfo,
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
- resetLockoutRequiresHardwareAuthToken);
+ resetLockoutRequiresHardwareAuthToken, sensorProps.sensorLocationX,
+ sensorProps.sensorLocationY, sensorProps.sensorRadius);
mMockHalResultController = controller;
mUserHasTrust = new SparseBooleanArray();
mTrustManager = context.getSystemService(TrustManager.class);
diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
index 1003c26..4918185 100644
--- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
@@ -35,7 +35,7 @@
public final class IrisAuthenticator extends IBiometricAuthenticator.Stub {
private final IIrisService mIrisService;
- public IrisAuthenticator(IIrisService irisService, int sensorId) throws RemoteException {
+ public IrisAuthenticator(IIrisService irisService, int sensorId) {
mIrisService = irisService;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java
index 08b2489..d684bb8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java
@@ -17,14 +17,26 @@
package com.android.server.biometrics.sensors.iris;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS;
import android.annotation.NonNull;
import android.content.Context;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.IBiometricService;
+import android.hardware.biometrics.SensorPropertiesInternal;
import android.hardware.iris.IIrisService;
+import android.os.Handler;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
+import java.util.List;
+
/**
* A service to manage multiple clients that want to access the Iris HAL API.
* The service is responsible for maintaining a list of clients and dispatching all
@@ -37,22 +49,54 @@
private static final String TAG = "IrisService";
+ private final IrisServiceWrapper mServiceWrapper;
+
/**
* Receives the incoming binder calls from IrisManager.
*/
private final class IrisServiceWrapper extends IIrisService.Stub {
@Override // Binder call
- public void initializeConfiguration(int sensorId, int strength) {
+ public void registerAuthenticators(@NonNull List<SensorPropertiesInternal> hidlSensors) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+
+ // Some HAL might not be started before the system service and will cause the code below
+ // to wait, and some of the operations below might take a significant amount of time to
+ // complete (calls to the HALs). To avoid blocking the rest of system server we put
+ // this on a background thread.
+ final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
+ true /* allowIo */);
+ thread.start();
+ final Handler handler = new Handler(thread.getLooper());
+
+ handler.post(() -> {
+ final IBiometricService biometricService = IBiometricService.Stub.asInterface(
+ ServiceManager.getService(Context.BIOMETRIC_SERVICE));
+
+ for (SensorPropertiesInternal hidlSensor : hidlSensors) {
+ final int sensorId = hidlSensor.sensorId;
+ final @BiometricManager.Authenticators.Types int strength =
+ Utils.propertyStrengthToAuthenticatorStrength(
+ hidlSensor.sensorStrength);
+ final IrisAuthenticator authenticator = new IrisAuthenticator(mServiceWrapper,
+ sensorId);
+ try {
+ biometricService.registerAuthenticator(sensorId, TYPE_IRIS, strength,
+ authenticator);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId);
+ }
+ }
+ });
}
}
public IrisService(@NonNull Context context) {
super(context);
+ mServiceWrapper = new IrisServiceWrapper();
}
@Override
public void onStart() {
- publishBinderService(Context.IRIS_SERVICE, new IrisServiceWrapper());
+ publishBinderService(Context.IRIS_SERVICE, mServiceWrapper);
}
}
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index cf4fe1e..05b12ba 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -16,14 +16,14 @@
package com.android.server.connectivity;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MAX_SAMPLES;
import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MIN_SAMPLES;
import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE;
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
@@ -33,6 +33,7 @@
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
+import android.net.ConnectivitySettingsManager;
import android.net.IDnsResolver;
import android.net.InetAddresses;
import android.net.LinkProperties;
@@ -131,11 +132,11 @@
* Get PrivateDnsConfig.
*/
public static PrivateDnsConfig getPrivateDnsConfig(Context context) {
- final String mode = ConnectivityManager.getPrivateDnsMode(context);
+ final int mode = ConnectivitySettingsManager.getPrivateDnsMode(context);
- final boolean useTls = !TextUtils.isEmpty(mode) && !PRIVATE_DNS_MODE_OFF.equals(mode);
+ final boolean useTls = mode != PRIVATE_DNS_MODE_OFF;
- if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(mode)) {
+ if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME == mode) {
final String specifier = getStringSetting(context.getContentResolver(),
PRIVATE_DNS_SPECIFIER);
return new PrivateDnsConfig(specifier, null);
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 4ecc759..091e6c4 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -27,6 +27,7 @@
import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
import static android.net.NetworkTemplate.OEM_MANAGED_ALL;
+import static android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -227,7 +228,8 @@
mNetworkTemplate = new NetworkTemplate(
NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId },
null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL);
+ NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT);
mUsageCallback = new UsageCallback() {
@Override
public void onThresholdReached(int networkType, String subscriberId) {
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index f572b46..bc0929c 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -55,6 +55,11 @@
private static final String TAG = ProxyTracker.class.getSimpleName();
private static final boolean DBG = true;
+ // EXTRA_PROXY_INFO is now @removed. In order to continue sending it, hardcode its value here.
+ // The Proxy.EXTRA_PROXY_INFO constant is not visible to this code because android.net.Proxy
+ // a hidden platform constant not visible to mainline modules.
+ private static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
+
@NonNull
private final Context mContext;
@@ -253,7 +258,7 @@
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxyInfo);
+ intent.putExtra(EXTRA_PROXY_INFO, proxyInfo);
final long ident = Binder.clearCallingIdentity();
try {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 2562c26..4bd1fd8 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -928,7 +928,6 @@
}
if (ArrayUtils.isEmpty(accounts)) {
- mLogger.log("scheduleSync: no accounts configured, dropping");
return;
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 0071b2f..2d7145f 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -34,6 +34,7 @@
import com.android.server.display.config.HighBrightnessMode;
import com.android.server.display.config.NitsMap;
import com.android.server.display.config.Point;
+import com.android.server.display.config.SensorDetails;
import com.android.server.display.config.XmlParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -75,6 +76,9 @@
private final Context mContext;
+ // The details of the ambient light sensor associated with this display.
+ private final SensorIdentifier mAmbientLightSensor = new SensorIdentifier();
+
// Nits and backlight values that are loaded from either the display device config file, or
// config.xml. These are the raw values and just used for the dumpsys
private float[] mRawNits;
@@ -249,6 +253,10 @@
return mBrightnessRampSlowIncrease;
}
+ SensorIdentifier getAmbientLightSensor() {
+ return mAmbientLightSensor;
+ }
+
/**
* @param quirkValue The quirk to test.
* @return {@code true} if the specified quirk is present in this configuration,
@@ -291,6 +299,7 @@
+ ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
+ ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease
+ ", mBrightnessRampSlowIncrease=" + mBrightnessRampSlowIncrease
+ + ", mAmbientLightSensor=" + mAmbientLightSensor
+ "}";
return str;
}
@@ -318,7 +327,7 @@
private static DisplayDeviceConfig getConfigFromPmValues(Context context) {
DisplayDeviceConfig config = new DisplayDeviceConfig(context);
- config.initFromPmValues();
+ config.initFromDefaultValues();
return config;
}
@@ -342,6 +351,7 @@
loadHighBrightnessModeData(config);
loadQuirks(config);
loadBrightnessRamps(config);
+ loadAmbientLightSensorFromDdc(config);
} else {
Slog.w(TAG, "DisplayDeviceConfig file is null");
}
@@ -357,9 +367,10 @@
loadBrightnessConstraintsFromConfigXml();
loadBrightnessMapFromConfigXml();
loadBrightnessRampsFromConfigXml();
+ loadAmbientLightSensorFromConfigXml();
}
- private void initFromPmValues() {
+ private void initFromDefaultValues() {
// Set all to basic values
mBacklightMinimum = PowerManager.BRIGHTNESS_MIN;
mBacklightMaximum = PowerManager.BRIGHTNESS_MAX;
@@ -369,6 +380,7 @@
mBrightnessRampSlowDecrease = PowerManager.BRIGHTNESS_MAX;
mBrightnessRampSlowIncrease = PowerManager.BRIGHTNESS_MAX;
setSimpleMappingStrategyValues();
+ loadAmbientLightSensorFromConfigXml();
}
private void loadBrightnessDefaultFromDdcXml(DisplayConfiguration config) {
@@ -637,6 +649,33 @@
mBrightnessRampSlowDecrease = mBrightnessRampSlowIncrease;
}
+ private void loadAmbientLightSensorFromConfigXml() {
+ mAmbientLightSensor.name = "";
+ mAmbientLightSensor.type = mContext.getResources().getString(
+ com.android.internal.R.string.config_displayLightSensorType);
+ }
+
+ private void loadAmbientLightSensorFromDdc(DisplayConfiguration config) {
+ final SensorDetails sensorDetails = config.getLightSensor();
+ if (sensorDetails != null) {
+ mAmbientLightSensor.type = sensorDetails.getType();
+ mAmbientLightSensor.name = sensorDetails.getName();
+ }
+ }
+
+ static class SensorIdentifier {
+ public String type;
+ public String name;
+
+ @Override
+ public String toString() {
+ return "Sensor{"
+ + "type: \"" + type + "\""
+ + ", name: \"" + name + "\""
+ + "} ";
+ }
+ }
+
/**
* Container for high brightness mode configuration data.
*/
@@ -656,6 +695,17 @@
/** Minimum time that HBM can be on before being enabled. */
public long timeMinMillis;
+ HighBrightnessModeData() {}
+
+ HighBrightnessModeData(float minimumLux, float transitionPoint,
+ long timeWindowMillis, long timeMaxMillis, long timeMinMillis) {
+ this.minimumLux = minimumLux;
+ this.transitionPoint = transitionPoint;
+ this.timeWindowMillis = timeWindowMillis;
+ this.timeMaxMillis = timeMaxMillis;
+ this.timeMinMillis = timeMinMillis;
+ }
+
/**
* Copies the HBM data to the specified parameter instance.
* @param other the instance to copy data to.
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 393a4eb..789f08f 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -55,6 +55,7 @@
import android.hardware.display.AmbientBrightnessDayStats;
import android.hardware.display.BrightnessChangeEvent;
import android.hardware.display.BrightnessConfiguration;
+import android.hardware.display.BrightnessInfo;
import android.hardware.display.Curve;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
@@ -430,8 +431,8 @@
mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
mUiHandler = UiThread.getHandler();
mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore);
- mLogicalDisplayMapper = new LogicalDisplayMapper(mDisplayDeviceRepo,
- new LogicalDisplayListener());
+ mLogicalDisplayMapper = new LogicalDisplayMapper(mContext, mDisplayDeviceRepo,
+ new LogicalDisplayListener(), mSyncRoot, mHandler);
mDisplayModeDirector = new DisplayModeDirector(context, mHandler);
mBrightnessSynchronizer = new BrightnessSynchronizer(mContext);
Resources resources = mContext.getResources();
@@ -842,8 +843,6 @@
return overriddenInfo;
}
-
-
return info;
}
@@ -1269,7 +1268,7 @@
DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
- dpc.onDisplayChangedLocked();
+ dpc.onDisplayChanged();
}
}
@@ -1305,12 +1304,23 @@
handleLogicalDisplayChangedLocked(display);
}
+ private void handleLogicalDisplayDeviceStateTransitionLocked(@NonNull LogicalDisplay display) {
+ final int displayId = display.getDisplayIdLocked();
+ final DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+ if (dpc != null) {
+ dpc.onDeviceStateTransition();
+ }
+ }
+
private Runnable updateDisplayStateLocked(DisplayDevice device) {
// Blank or unblank the display immediately to match the state requested
// by the display power controller (if known).
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
+ if (display == null) {
+ return null;
+ }
final int displayId = display.getDisplayIdLocked();
final int state = mDisplayStates.get(displayId);
@@ -1454,9 +1464,12 @@
clearViewportsLocked();
// Configure each display device.
- mDisplayDeviceRepo.forEachLocked((DisplayDevice device) -> {
- configureDisplayLocked(t, device);
- device.performTraversalLocked(t);
+ mLogicalDisplayMapper.forEachLocked((LogicalDisplay display) -> {
+ final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
+ if (device != null) {
+ configureDisplayLocked(t, device);
+ device.performTraversalLocked(t);
+ }
});
// Tell the input system about these new viewports.
@@ -2062,10 +2075,16 @@
display, mContext);
final DisplayPowerController displayPowerController = new DisplayPowerController(
mContext, mDisplayPowerCallbacks, mPowerHandler, mSensorManager,
- mDisplayBlanker, display, mBrightnessTracker, brightnessSetting);
+ mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
+ () -> handleBrightnessChange(display));
mDisplayPowerControllers.append(display.getDisplayIdLocked(), displayPowerController);
}
+ private void handleBrightnessChange(LogicalDisplay display) {
+ sendDisplayEventLocked(display.getDisplayIdLocked(),
+ DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED);
+ }
+
private final class DisplayManagerHandler extends Handler {
public DisplayManagerHandler(Looper looper) {
super(looper, null, true /*async*/);
@@ -2154,6 +2173,10 @@
case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED:
handleLogicalDisplayFrameRateOverridesChangedLocked(display);
break;
+
+ case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION:
+ handleLogicalDisplayDeviceStateTransitionLocked(display);
+ break;
}
}
@@ -2219,6 +2242,8 @@
return (mask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0;
case DisplayManagerGlobal.EVENT_DISPLAY_CHANGED:
return (mask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0;
+ case DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED:
+ return (mask & DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0;
case DisplayManagerGlobal.EVENT_DISPLAY_REMOVED:
return (mask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0;
default:
@@ -2781,6 +2806,25 @@
}
}
+ @Override
+ public BrightnessInfo getBrightnessInfo(int displayId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS,
+ "Permission required to read the display's brightness info.");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mSyncRoot) {
+ DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+ if (dpc != null) {
+ return dpc.getBrightnessInfo();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return null;
+ }
+
@Override // Binder call
public boolean isMinimalPostProcessingRequested(int displayId) {
synchronized (mSyncRoot) {
@@ -3232,4 +3276,17 @@
}
}
};
+
+ /**
+ * Functional interface for providing time.
+ * TODO(b/184781936): merge with PowerManagerService.Clock
+ */
+ @VisibleForTesting
+ public interface Clock {
+ /**
+ * Returns current time in milliseconds since boot, not counting time spent in deep sleep.
+ */
+ long uptimeMillis();
+ }
+
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 5cd0534..3340e3c 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -32,6 +32,7 @@
import android.hardware.display.AmbientBrightnessDayStats;
import android.hardware.display.BrightnessChangeEvent;
import android.hardware.display.BrightnessConfiguration;
+import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.metrics.LogMaker;
@@ -53,6 +54,7 @@
import android.util.TimeUtils;
import android.view.Display;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.display.BrightnessSynchronizer;
import com.android.internal.logging.MetricsLogger;
@@ -146,6 +148,9 @@
private static final int REPORTED_TO_POLICY_SCREEN_ON = 2;
private static final int REPORTED_TO_POLICY_SCREEN_TURNING_OFF = 3;
+ private static final Uri BRIGHTNESS_FLOAT_URI =
+ Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FLOAT);
+
private final Object mLock = new Object();
private final Context mContext;
@@ -215,6 +220,9 @@
// Whether or not the color fade on screen on / off is enabled.
private final boolean mColorFadeEnabled;
+ @GuardedBy("mCachedBrightnessInfo")
+ private final CachedBrightnessInfo mCachedBrightnessInfo = new CachedBrightnessInfo();
+
// True if we should fade the screen while turning it off, false if we should play
// a stylish color fade animation instead.
private boolean mColorFadeFadesConfig;
@@ -359,6 +367,8 @@
private final BrightnessSetting mBrightnessSetting;
+ private final Runnable mOnBrightnessChangeRunnable;
+
// A record of state for skipping brightness ramps.
private int mSkipRampState = RAMP_STATE_SKIP_NONE;
@@ -368,6 +378,8 @@
// The controller for the automatic brightness level.
private AutomaticBrightnessController mAutomaticBrightnessController;
+ private Sensor mLightSensor;
+
// The mapper between ambient lux, display backlight values, and display brightness.
@Nullable
private BrightnessMappingStrategy mBrightnessMapper;
@@ -418,13 +430,16 @@
// True if this DisplayPowerController has been stopped and should no longer be running.
private boolean mStopped;
+ private DisplayDeviceConfig mDisplayDeviceConfig;
+
/**
* Creates the display power controller.
*/
public DisplayPowerController(Context context,
DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager, DisplayBlanker blanker, LogicalDisplay logicalDisplay,
- BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting) {
+ BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting,
+ Runnable onBrightnessChangeRunnable) {
mLogicalDisplay = logicalDisplay;
mDisplayId = mLogicalDisplay.getDisplayIdLocked();
mHandler = new DisplayControllerHandler(handler.getLooper());
@@ -442,8 +457,9 @@
mBlanker = blanker;
mContext = context;
mBrightnessTracker = brightnessTracker;
-
mBrightnessSetting = brightnessSetting;
+ mOnBrightnessChangeRunnable = onBrightnessChangeRunnable;
+
PowerManager pm = context.getSystemService(PowerManager.class);
final Resources resources = context.getResources();
@@ -478,17 +494,20 @@
com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing);
- DisplayDeviceConfig displayDeviceConfig = logicalDisplay
+ mDisplayDeviceConfig = logicalDisplay
.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig();
- mBrightnessRampRateFastDecrease = displayDeviceConfig.getBrightnessRampFastDecrease();
- mBrightnessRampRateFastIncrease = displayDeviceConfig.getBrightnessRampFastIncrease();
- mBrightnessRampRateSlowDecrease = displayDeviceConfig.getBrightnessRampSlowDecrease();
- mBrightnessRampRateSlowIncrease = displayDeviceConfig.getBrightnessRampSlowIncrease();
+ mBrightnessRampRateFastDecrease = mDisplayDeviceConfig.getBrightnessRampFastDecrease();
+ mBrightnessRampRateFastIncrease = mDisplayDeviceConfig.getBrightnessRampFastIncrease();
+ mBrightnessRampRateSlowDecrease = mDisplayDeviceConfig.getBrightnessRampSlowDecrease();
+ mBrightnessRampRateSlowIncrease = mDisplayDeviceConfig.getBrightnessRampSlowIncrease();
mSkipScreenOnBrightnessRamp = resources.getBoolean(
com.android.internal.R.bool.config_skipScreenOnBrightnessRamp);
mHbmController = createHbmController();
+ // Seed the cached brightness
+ saveBrightnessInfo(getScreenBrightnessSetting());
+
if (mUseSoftwareAutoBrightnessConfig) {
final float dozeScaleFactor = resources.getFraction(
com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor,
@@ -534,16 +553,12 @@
+ "config_autoBrightnessLightSensorRate (" + lightSensorRate + ").");
}
- String lightSensorType = resources.getString(
- com.android.internal.R.string.config_displayLightSensorType);
- Sensor lightSensor = findDisplayLightSensor(lightSensorType);
+ loadAmbientLightSensor();
- final DisplayDeviceConfig ddc =
- logicalDisplay.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig();
- mBrightnessMapper = BrightnessMappingStrategy.create(resources, ddc);
+ mBrightnessMapper = BrightnessMappingStrategy.create(resources, mDisplayDeviceConfig);
if (mBrightnessMapper != null) {
mAutomaticBrightnessController = new AutomaticBrightnessController(this,
- handler.getLooper(), sensorManager, lightSensor, mBrightnessMapper,
+ handler.getLooper(), sensorManager, mLightSensor, mBrightnessMapper,
lightSensorWarmUpTimeConfig, PowerManager.BRIGHTNESS_MIN,
PowerManager.BRIGHTNESS_MAX, dozeScaleFactor, lightSensorRate,
initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
@@ -597,8 +612,8 @@
mDisplayWhiteBalanceSettings = displayWhiteBalanceSettings;
mDisplayWhiteBalanceController = displayWhiteBalanceController;
- if (displayDeviceConfig != null && displayDeviceConfig.getNits() != null) {
- mNitsRange = displayDeviceConfig.getNits();
+ if (mDisplayDeviceConfig != null && mDisplayDeviceConfig.getNits() != null) {
+ mNitsRange = mDisplayDeviceConfig.getNits();
} else {
Slog.w(TAG, "Screen brightness nits configuration is unavailable; falling back");
mNitsRange = BrightnessMappingStrategy.getFloatArray(context.getResources()
@@ -638,17 +653,19 @@
mBrightnessMapper.recalculateSplines(mCdsi.isReduceBrightColorsActivated(), adjustedNits);
}
- private Sensor findDisplayLightSensor(String sensorType) {
- if (!TextUtils.isEmpty(sensorType)) {
- List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
- for (int i = 0; i < sensors.size(); i++) {
- Sensor sensor = sensors.get(i);
- if (sensorType.equals(sensor.getStringType())) {
+ private Sensor findSensor(String sensorType, String sensorName, int fallbackType) {
+ final boolean isNameSpecified = !TextUtils.isEmpty(sensorName);
+ final boolean isTypeSpecified = !TextUtils.isEmpty(sensorType);
+ List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
+ if (isNameSpecified || isTypeSpecified) {
+ for (Sensor sensor : sensors) {
+ if ((!isNameSpecified || sensorName.equals(sensor.getName()))
+ && (!isTypeSpecified || sensorType.equals(sensor.getStringType()))) {
return sensor;
}
}
}
- return mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+ return mSensorManager.getDefaultSensor(fallbackType);
}
/**
@@ -763,10 +780,21 @@
* when displays get swapped on foldable devices. For example, different brightness properties
* of each display need to be properly reflected in AutomaticBrightnessController.
*/
- public void onDisplayChangedLocked() {
+ public void onDisplayChanged() {
// TODO: b/175821789 - Support high brightness on multiple (folding) displays
-
mUniqueDisplayId = mLogicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
+ mDisplayDeviceConfig = mLogicalDisplay.getPrimaryDisplayDeviceLocked()
+ .getDisplayDeviceConfig();
+ loadAmbientLightSensor();
+ }
+
+ /**
+ * Called when the displays are preparing to transition from one device state to another.
+ * This process involves turning off some displays so we need updatePowerState() to run and
+ * calculate the new state.
+ */
+ public void onDeviceStateTransition() {
+ sendUpdatePowerState();
}
/**
@@ -1004,7 +1032,9 @@
mIgnoreProximityUntilChanged = false;
}
- if (!mLogicalDisplay.isEnabled() || mScreenOffBecauseOfProximity) {
+ if (!mLogicalDisplay.isEnabled()
+ || mLogicalDisplay.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION
+ || mScreenOffBecauseOfProximity) {
state = Display.STATE_OFF;
}
@@ -1158,6 +1188,10 @@
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_MANUAL);
}
+ // Save out the brightness info now that the brightness state for this iteration has been
+ // finalized and before we send out notifications about the brightness changing.
+ saveBrightnessInfo(brightnessState);
+
if (updateScreenBrightnessSetting) {
// Tell the rest of the system about the new brightness in case we had to change it
// for things like auto-brightness or high-brightness-mode. Note that we do this
@@ -1390,13 +1424,36 @@
msg.sendToTarget();
}
+ public BrightnessInfo getBrightnessInfo() {
+ synchronized (mCachedBrightnessInfo) {
+ return new BrightnessInfo(
+ mCachedBrightnessInfo.brightness,
+ mCachedBrightnessInfo.brightnessMin,
+ mCachedBrightnessInfo.brightnessMax,
+ mCachedBrightnessInfo.hbmMode);
+ }
+ }
+
+ private void saveBrightnessInfo(float brightness) {
+ synchronized (mCachedBrightnessInfo) {
+ mCachedBrightnessInfo.brightness = brightness;
+ mCachedBrightnessInfo.brightnessMin = mHbmController.getCurrentBrightnessMin();
+ mCachedBrightnessInfo.brightnessMax = mHbmController.getCurrentBrightnessMax();
+ mCachedBrightnessInfo.hbmMode = mHbmController.getHighBrightnessMode();
+ }
+ }
+
private HighBrightnessModeController createHbmController() {
final DisplayDeviceConfig ddConfig =
mLogicalDisplay.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig();
final DisplayDeviceConfig.HighBrightnessModeData hbmData =
ddConfig != null ? ddConfig.getHighBrightnessModeData() : null;
return new HighBrightnessModeController(mHandler, PowerManager.BRIGHTNESS_MIN,
- PowerManager.BRIGHTNESS_MAX, hbmData, () -> sendUpdatePowerStateLocked());
+ PowerManager.BRIGHTNESS_MAX, hbmData,
+ () -> {
+ sendUpdatePowerStateLocked();
+ mHandler.post(mOnBrightnessChangeRunnable);
+ });
}
private void blockScreenOn() {
@@ -1510,6 +1567,14 @@
mReportedScreenStateToPolicy = state;
}
+ private void loadAmbientLightSensor() {
+ DisplayDeviceConfig.SensorIdentifier lightSensor =
+ mDisplayDeviceConfig.getAmbientLightSensor();
+ String lightSensorName = lightSensor.name;
+ String lightSensorType = lightSensor.type;
+ mLightSensor = findSensor(lightSensorType, lightSensorName, Sensor.TYPE_LIGHT);
+ }
+
private float clampScreenBrightnessForVr(float value) {
return MathUtils.constrain(
value, mScreenBrightnessForVrRangeMinimum,
@@ -1819,7 +1884,7 @@
mPendingScreenBrightnessSetting = getScreenBrightnessSetting();
if (userSwitch) {
// Don't treat user switches as user initiated change.
- mCurrentScreenBrightnessSetting = mPendingScreenBrightnessSetting;
+ setCurrentScreenBrightness(mPendingScreenBrightnessSetting);
if (mAutomaticBrightnessController != null) {
mAutomaticBrightnessController.resetShortTermModel();
}
@@ -1858,11 +1923,18 @@
private void putScreenBrightnessSetting(float brightnessValue, boolean updateCurrent) {
if (updateCurrent) {
- mCurrentScreenBrightnessSetting = brightnessValue;
+ setCurrentScreenBrightness(brightnessValue);
}
mBrightnessSetting.setBrightness(brightnessValue);
}
+ private void setCurrentScreenBrightness(float brightnessValue) {
+ if (brightnessValue != mCurrentScreenBrightnessSetting) {
+ mCurrentScreenBrightnessSetting = brightnessValue;
+ mHandler.post(mOnBrightnessChangeRunnable);
+ }
+ }
+
private void putAutoBrightnessAdjustmentSetting(float adjustment) {
if (mDisplayId == Display.DEFAULT_DISPLAY) {
mAutoBrightnessAdjustment = adjustment;
@@ -1895,7 +1967,7 @@
mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
return false;
}
- mCurrentScreenBrightnessSetting = mPendingScreenBrightnessSetting;
+ setCurrentScreenBrightness(mPendingScreenBrightnessSetting);
mLastUserSetScreenBrightness = mPendingScreenBrightnessSetting;
mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
@@ -1987,6 +2059,7 @@
pw.println();
pw.println("Display Power Controller:");
pw.println(" mDisplayId=" + mDisplayId);
+ pw.println(" mLightSensor=" + mLightSensor);
pw.println();
pw.println("Display Power Controller Locked State:");
@@ -2037,10 +2110,10 @@
pw.println(" mPendingProximityDebounceTime="
+ TimeUtils.formatUptime(mPendingProximityDebounceTime));
pw.println(" mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
- pw.println(" mLastUserSetScreenBrightnessFloat=" + mLastUserSetScreenBrightness);
- pw.println(" mPendingScreenBrightnessSettingFloat="
+ pw.println(" mLastUserSetScreenBrightness=" + mLastUserSetScreenBrightness);
+ pw.println(" mPendingScreenBrightnessSetting="
+ mPendingScreenBrightnessSetting);
- pw.println(" mTemporaryScreenBrightnessFloat=" + mTemporaryScreenBrightness);
+ pw.println(" mTemporaryScreenBrightness=" + mTemporaryScreenBrightness);
pw.println(" mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment);
pw.println(" mBrightnessReason=" + mBrightnessReason);
pw.println(" mTemporaryAutoBrightnessAdjustment=" + mTemporaryAutoBrightnessAdjustment);
@@ -2083,6 +2156,10 @@
mAutomaticBrightnessController.dump(pw);
}
+ if (mHbmController != null) {
+ mHbmController.dump(pw);
+ }
+
pw.println();
if (mDisplayWhiteBalanceController != null) {
mDisplayWhiteBalanceController.dump(pw);
@@ -2411,4 +2488,11 @@
}
}
}
+
+ static class CachedBrightnessInfo {
+ public float brightness;
+ public float brightnessMin;
+ public float brightnessMax;
+ public int hbmMode;
+ }
}
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index 2e5561d..e6486bd 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -16,13 +16,17 @@
package com.android.server.display;
+import android.hardware.display.BrightnessInfo;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
+import com.android.server.display.DisplayManagerService.Clock;
+import java.io.PrintWriter;
import java.util.Iterator;
import java.util.LinkedList;
@@ -45,11 +49,13 @@
private final Handler mHandler;
private final Runnable mHbmChangeCallback;
private final Runnable mRecalcRunnable;
+ private final Clock mClock;
private boolean mIsInAllowedAmbientRange = false;
private boolean mIsTimeAvailable = false;
private boolean mIsAutoBrightnessEnabled = false;
private float mAutoBrightness;
+ private int mHbmMode = BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
/**
* If HBM is currently running, this is the start time for the current HBM session.
@@ -65,28 +71,25 @@
HighBrightnessModeController(Handler handler, float brightnessMin, float brightnessMax,
HighBrightnessModeData hbmData, Runnable hbmChangeCallback) {
+ this(SystemClock::uptimeMillis, handler, brightnessMin, brightnessMax, hbmData,
+ hbmChangeCallback);
+ }
+
+ @VisibleForTesting
+ HighBrightnessModeController(Clock clock, Handler handler, float brightnessMin,
+ float brightnessMax, HighBrightnessModeData hbmData, Runnable hbmChangeCallback) {
+ mClock = clock;
mHandler = handler;
mBrightnessMin = brightnessMin;
mBrightnessMax = brightnessMax;
mHbmData = hbmData;
mHbmChangeCallback = hbmChangeCallback;
mAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
-
- mRecalcRunnable = () -> {
- boolean oldIsAllowed = isCurrentlyAllowed();
- recalculateTimeAllowance();
- if (oldIsAllowed != isCurrentlyAllowed()) {
- // Our allowed state has changed; tell AutomaticBrightnessController
- // to update the brightness.
- if (mHbmChangeCallback != null) {
- mHbmChangeCallback.run();
- }
- }
- };
+ mRecalcRunnable = this::recalculateTimeAllowance;
}
void setAutoBrightnessEnabled(boolean isEnabled) {
- if (isEnabled == mIsAutoBrightnessEnabled) {
+ if (!deviceSupportsHbm() || isEnabled == mIsAutoBrightnessEnabled) {
return;
}
if (DEBUG) {
@@ -94,6 +97,7 @@
}
mIsAutoBrightnessEnabled = isEnabled;
mIsInAllowedAmbientRange = false; // reset when auto-brightness switches
+ recalculateTimeAllowance();
}
float getCurrentBrightnessMin() {
@@ -137,7 +141,7 @@
final boolean wasOldBrightnessHigh = oldAutoBrightness > mHbmData.transitionPoint;
final boolean isNewBrightnessHigh = mAutoBrightness > mHbmData.transitionPoint;
if (wasOldBrightnessHigh != isNewBrightnessHigh) {
- final long currentTime = SystemClock.uptimeMillis();
+ final long currentTime = mClock.uptimeMillis();
if (isNewBrightnessHigh) {
mRunningStartTimeMillis = currentTime;
} else {
@@ -153,6 +157,21 @@
recalculateTimeAllowance();
}
+ int getHighBrightnessMode() {
+ return mHbmMode;
+ }
+
+ void dump(PrintWriter pw) {
+ pw.println("HighBrightnessModeController:");
+ pw.println(" mBrightnessMin=" + mBrightnessMin);
+ pw.println(" mBrightnessMax=" + mBrightnessMax);
+ pw.println(" mHbmData=" + mHbmData);
+ pw.println(" mIsInAllowedAmbientRange=" + mIsInAllowedAmbientRange);
+ pw.println(" mIsTimeAvailable= " + mIsTimeAvailable);
+ pw.println(" mIsAutoBrightnessEnabled=" + mIsAutoBrightnessEnabled);
+ pw.println(" mAutoBrightness=" + mAutoBrightness);
+ }
+
private boolean isCurrentlyAllowed() {
return mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange;
}
@@ -165,7 +184,7 @@
* Recalculates the allowable HBM time.
*/
private void recalculateTimeAllowance() {
- final long currentTime = SystemClock.uptimeMillis();
+ final long currentTime = mClock.uptimeMillis();
long timeAlreadyUsed = 0;
// First, lets see how much time we've taken for any currently running
@@ -247,8 +266,22 @@
if (nextTimeout != -1) {
mHandler.removeCallbacks(mRecalcRunnable);
- mHandler.postAtTime(mRecalcRunnable, nextTimeout);
+ mHandler.postAtTime(mRecalcRunnable, nextTimeout + 1);
}
+
+ // Update the state of the world
+ int newHbmMode = calculateHighBrightnessMode();
+ if (mHbmMode != newHbmMode) {
+ mHbmMode = newHbmMode;
+ mHbmChangeCallback.run();
+ }
+ }
+
+ private int calculateHighBrightnessMode() {
+ if (deviceSupportsHbm() && isCurrentlyAllowed()) {
+ return BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT;
+ }
+ return BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
}
/**
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 1589419..9acb4c8 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -16,6 +16,7 @@
package com.android.server.display;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Point;
@@ -65,6 +66,33 @@
final class LogicalDisplay {
private static final String TAG = "LogicalDisplay";
+ /**
+ * Phase indicating the logical display's existence is hidden from the rest of the framework.
+ * This can happen if the current layout has specifically requested to keep this display
+ * disabled.
+ */
+ static final int DISPLAY_PHASE_DISABLED = -1;
+
+ /**
+ * Phase indicating that the logical display is going through a layout transition.
+ * When in this phase, other systems can choose to special case power-state handling of a
+ * display that might be in a transition.
+ */
+ static final int DISPLAY_PHASE_LAYOUT_TRANSITION = 0;
+
+ /**
+ * The display is exposed to the rest of the system and its power state is determined by a
+ * power-request from PowerManager.
+ */
+ static final int DISPLAY_PHASE_ENABLED = 1;
+
+ @IntDef(prefix = {"DISPLAY_PHASE" }, value = {
+ DISPLAY_PHASE_DISABLED,
+ DISPLAY_PHASE_LAYOUT_TRANSITION,
+ DISPLAY_PHASE_ENABLED
+ })
+ @interface DisplayPhase {}
+
// The layer stack we use when the display has been blanked to prevent any
// of its content from appearing.
private static final int BLANK_LAYER_STACK = -1;
@@ -129,10 +157,12 @@
private final Rect mTempDisplayRect = new Rect();
/**
- * Indicates that the Logical display is enabled (default). See {@link #setEnabled} for
- * more information.
+ * Indicates the current phase of the display. Generally, phases supersede any
+ * requests from PowerManager in DPC's calculation for the display state. Only when the
+ * phase is ENABLED does PowerManager's request for the display take effect.
*/
- private boolean mIsEnabled = true;
+ @DisplayPhase
+ private int mPhase = DISPLAY_PHASE_ENABLED;
/**
* The UID mappings for refresh rate override
@@ -721,27 +751,32 @@
return old;
}
- /**
- * Sets the LogicalDisplay to be enabled or disabled. If the display is not enabled,
- * the system will always set the display to power off, regardless of the global state of the
- * device.
- * TODO: b/170498827 - Remove when updateDisplayStateLocked is updated.
- */
- public void setEnabled(boolean isEnabled) {
- mIsEnabled = isEnabled;
+ public void setPhase(@DisplayPhase int phase) {
+ mPhase = phase;
}
/**
- * @return {@code true} iff the LogicalDisplay is enabled or {@code false}
- * if disabled indicating that the display has been forced to be OFF.
+ * Returns the currently set phase for this LogicalDisplay. Phases are used when transitioning
+ * from one device state to another. {@see LogicalDisplayMapper}.
+ */
+ @DisplayPhase
+ public int getPhase() {
+ return mPhase;
+ }
+
+ /**
+ * @return {@code true} if the LogicalDisplay is enabled or {@code false}
+ * if disabled indicating that the display should be hidden from the rest of the apps and
+ * framework.
*/
public boolean isEnabled() {
- return mIsEnabled;
+ // DISPLAY_PHASE_LAYOUT_TRANSITION is still considered an 'enabled' phase.
+ return mPhase == DISPLAY_PHASE_ENABLED || mPhase == DISPLAY_PHASE_LAYOUT_TRANSITION;
}
public void dumpLocked(PrintWriter pw) {
pw.println("mDisplayId=" + mDisplayId);
- pw.println("mIsEnabled=" + mIsEnabled);
+ pw.println("mPhase=" + mPhase);
pw.println("mLayerStack=" + mLayerStack);
pw.println("mHasContent=" + mHasContent);
pw.println("mDesiredDisplayModeSpecs={" + mDesiredDisplayModeSpecs + "}");
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index fcfa674..4c9a2d7 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -16,18 +16,24 @@
package com.android.server.display;
+import android.annotation.NonNull;
+import android.content.Context;
import android.hardware.devicestate.DeviceStateManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.view.Display;
import android.view.DisplayAddress;
import android.view.DisplayInfo;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.LogicalDisplay.DisplayPhase;
import com.android.server.display.layout.Layout;
import java.io.PrintWriter;
@@ -55,11 +61,20 @@
public static final int LOGICAL_DISPLAY_EVENT_REMOVED = 3;
public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 4;
public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 5;
+ public static final int LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION = 6;
public static final int DISPLAY_GROUP_EVENT_ADDED = 1;
public static final int DISPLAY_GROUP_EVENT_CHANGED = 2;
public static final int DISPLAY_GROUP_EVENT_REMOVED = 3;
+ private static final int TIMEOUT_STATE_TRANSITION_MILLIS = 500;
+
+ private static final int MSG_TRANSITION_TO_PENDING_DEVICE_STATE = 1;
+
+ private static final int UPDATE_STATE_NEW = 0;
+ private static final int UPDATE_STATE_TRANSITION = 1;
+ private static final int UPDATE_STATE_UPDATED = 2;
+
/**
* Temporary display info, used for comparing display configurations.
*/
@@ -76,6 +91,11 @@
private final boolean mSingleDisplayDemoMode;
/**
+ * True if the device can have more than one internal display on at a time.
+ */
+ private final boolean mSupportsConcurrentInternalDisplays;
+
+ /**
* Map of all logical displays indexed by logical display id.
* Any modification to mLogicalDisplays must invalidate the DisplayManagerGlobal cache.
* TODO: multi-display - Move the aforementioned comment?
@@ -89,13 +109,16 @@
private final DisplayDeviceRepository mDisplayDeviceRepo;
private final DeviceStateToLayoutMap mDeviceStateToLayoutMap;
private final Listener mListener;
+ private final DisplayManagerService.SyncRoot mSyncRoot;
+ private final LogicalDisplayMapperHandler mHandler;
/**
* Has an entry for every logical display that the rest of the system has been notified about.
* Any entry in here requires us to send a {@link LOGICAL_DISPLAY_EVENT_REMOVED} event when it
- * is deleted or {@link LOGICAL_DISPLAY_EVENT_CHANGED} when it is changed.
+ * is deleted or {@link LOGICAL_DISPLAY_EVENT_CHANGED} when it is changed. The values are any
+ * of the {@code UPDATE_STATE_*} constant types.
*/
- private final SparseBooleanArray mUpdatedLogicalDisplays = new SparseBooleanArray();
+ private final SparseIntArray mUpdatedLogicalDisplays = new SparseIntArray();
/**
* Keeps track of all the display groups that we already told other people about. IOW, if a
@@ -119,11 +142,18 @@
private int mNextNonDefaultGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
private Layout mCurrentLayout = null;
private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
+ private int mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
- LogicalDisplayMapper(DisplayDeviceRepository repo, Listener listener) {
+ LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
+ @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
+ @NonNull Handler handler) {
+ mSyncRoot = syncRoot;
+ mHandler = new LogicalDisplayMapperHandler(handler.getLooper());
mDisplayDeviceRepo = repo;
mListener = listener;
mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
+ mSupportsConcurrentInternalDisplays = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_supportsConcurrentInternalDisplays);
mDisplayDeviceRepo.addListener(this);
mDeviceStateToLayoutMap = new DeviceStateToLayoutMap();
}
@@ -142,6 +172,7 @@
if (DEBUG) {
Slog.d(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());
}
+ finishStateTransitionLocked(false /*force*/);
updateLogicalDisplaysLocked();
break;
@@ -166,7 +197,7 @@
public LogicalDisplay getDisplayLocked(DisplayDevice device) {
final int count = mLogicalDisplays.size();
for (int i = 0; i < count; i++) {
- LogicalDisplay display = mLogicalDisplays.valueAt(i);
+ final LogicalDisplay display = mLogicalDisplays.valueAt(i);
if (display.getPrimaryDisplayDeviceLocked() == device) {
return display;
}
@@ -198,6 +229,7 @@
}
}
+ @VisibleForTesting
public int getDisplayGroupIdFromDisplayIdLocked(int displayId) {
final LogicalDisplay display = getDisplayLocked(displayId);
if (display == null) {
@@ -225,7 +257,6 @@
ipw.increaseIndent();
ipw.println("mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
-
ipw.println("mCurrentLayout=" + mCurrentLayout);
final int logicalDisplayCount = mLogicalDisplays.size();
@@ -244,19 +275,78 @@
}
void setDeviceStateLocked(int state) {
- if (state != mDeviceState) {
- resetLayoutLocked();
- mDeviceState = state;
- applyLayoutLocked();
- updateLogicalDisplaysLocked();
+ Slog.i(TAG, "Requesting Transition to state: " + state);
+ // As part of a state transition, we may need to turn off some displays temporarily so that
+ // the transition is smooth. Plus, on some devices, only one internal displays can be
+ // on at a time. We use DISPLAY_PHASE_LAYOUT_TRANSITION to mark a display that needs to be
+ // temporarily turned off.
+ if (mDeviceState != DeviceStateManager.INVALID_DEVICE_STATE) {
+ resetLayoutLocked(mDeviceState, state, LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION);
+ }
+ mPendingDeviceState = state;
+ if (areAllTransitioningDisplaysOffLocked()) {
+ // Nothing to wait on, we're good to go
+ transitionToPendingStateLocked();
+ return;
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "Postponing transition to state: " + mPendingDeviceState);
+ }
+ // Send the transitioning phase updates to DisplayManager so that the displays can
+ // start turning OFF in preparation for the new layout.
+ updateLogicalDisplaysLocked();
+ mHandler.sendEmptyMessageDelayed(MSG_TRANSITION_TO_PENDING_DEVICE_STATE,
+ TIMEOUT_STATE_TRANSITION_MILLIS);
+ }
+
+ private boolean areAllTransitioningDisplaysOffLocked() {
+ final int count = mLogicalDisplays.size();
+ for (int i = 0; i < count; i++) {
+ final LogicalDisplay display = mLogicalDisplays.valueAt(i);
+ if (display.getPhase() != LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION) {
+ continue;
+ }
+
+ final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
+ if (device != null) {
+ final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+ if (info.state != Display.STATE_OFF) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private void transitionToPendingStateLocked() {
+ resetLayoutLocked(mDeviceState, mPendingDeviceState, LogicalDisplay.DISPLAY_PHASE_ENABLED);
+ mDeviceState = mPendingDeviceState;
+ mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
+ applyLayoutLocked();
+ updateLogicalDisplaysLocked();
+ }
+
+ private void finishStateTransitionLocked(boolean force) {
+ if (mPendingDeviceState == DeviceStateManager.INVALID_DEVICE_STATE) {
+ return;
+ }
+
+ final boolean displaysOff = areAllTransitioningDisplaysOffLocked();
+ if (displaysOff || force) {
+ transitionToPendingStateLocked();
+ mHandler.removeMessages(MSG_TRANSITION_TO_PENDING_DEVICE_STATE);
+ } else if (DEBUG) {
+ Slog.d(TAG, "Not yet ready to transition to state=" + mPendingDeviceState
+ + " with displays-off=" + displaysOff + " and force=" + force);
}
}
private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
// Internal Displays need to have additional initialization.
- // TODO: b/168208162 - This initializes a default dynamic display layout for INTERNAL
- // devices, which will eventually just be a fallback in case no static layout definitions
+ // This initializes a default dynamic display layout for INTERNAL
+ // devices, which is used as a fallback in case no static layout definitions
// exist or cannot be loaded.
if (deviceInfo.type == Display.TYPE_INTERNAL) {
initializeInternalDisplayDeviceLocked(device);
@@ -289,7 +379,8 @@
display.updateLocked(mDisplayDeviceRepo);
final DisplayInfo newDisplayInfo = display.getDisplayInfoLocked();
- final boolean wasPreviouslyUpdated = mUpdatedLogicalDisplays.get(displayId);
+ final int updateState = mUpdatedLogicalDisplays.get(displayId, UPDATE_STATE_NEW);
+ final boolean wasPreviouslyUpdated = updateState != UPDATE_STATE_NEW;
// The display is no longer valid and needs to be removed.
if (!display.isValidLocked()) {
@@ -331,6 +422,10 @@
assignDisplayGroupLocked(display);
mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED);
+ } else if (updateState == UPDATE_STATE_TRANSITION) {
+ mLogicalDisplaysToUpdate.put(displayId,
+ LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION);
+
// Display frame rate overrides changed.
} else if (!display.getPendingFrameRateOverrideUids().isEmpty()) {
mLogicalDisplaysToUpdate.put(
@@ -347,7 +442,7 @@
}
}
- mUpdatedLogicalDisplays.put(displayId, true);
+ mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_UPDATED);
}
// Go through the groups and do the same thing. We do this after displays since group
@@ -376,12 +471,13 @@
// Send the display and display group updates in order by message type. This is important
// to ensure that addition and removal notifications happen in the right order.
+ sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION);
sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_ADDED);
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_REMOVED);
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CHANGED);
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
- sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_ADDED);
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_SWAPPED);
+ sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_ADDED);
sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_CHANGED);
sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_REMOVED);
@@ -400,7 +496,14 @@
}
final int id = mLogicalDisplaysToUpdate.keyAt(i);
- mListener.onLogicalDisplayEventLocked(getDisplayLocked(id), msg);
+ final LogicalDisplay display = getDisplayLocked(id);
+ if (DEBUG) {
+ final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
+ final String uniqueId = device == null ? "null" : device.getUniqueId();
+ Slog.d(TAG, "Sending " + displayEventToString(msg) + " for display=" + id
+ + " with device=" + uniqueId);
+ }
+ mListener.onLogicalDisplayEventLocked(display, msg);
if (msg == LOGICAL_DISPLAY_EVENT_REMOVED) {
// We wait until we sent the EVENT_REMOVED event before actually removing the
// display.
@@ -464,36 +567,81 @@
}
/**
- * Resets the current layout in preparation for a new layout. Layouts can specify if some
- * displays should be disabled (OFF). When switching from one layout to another, we go
- * through each of the displays and make sure any displays we might have disabled are
- * enabled again.
+ * Goes through all the displays used in the layouts for the specified {@code fromState} and
+ * {@code toState} and applies the specified {@code phase}. When a new layout is requested, we
+ * put the displays that will change into a transitional phase so that they can all be turned
+ * OFF. Once all are confirmed OFF, then this method gets called again to reset the phase to
+ * normal operation. This helps to ensure that all display-OFF requests are made before
+ * display-ON which in turn hides any resizing-jank windows might incur when switching displays.
+ *
+ * @param fromState The state we are switching from.
+ * @param toState The state we are switching to.
+ * @param phase The new phase to apply to the displays.
*/
- private void resetLayoutLocked() {
- final Layout layout = mDeviceStateToLayoutMap.get(mDeviceState);
- for (int i = layout.size() - 1; i >= 0; i--) {
- final Layout.Display displayLayout = layout.getAt(i);
- final LogicalDisplay display = getDisplayLocked(displayLayout.getLogicalDisplayId());
- if (display != null) {
- enableDisplayLocked(display, true); // Reset all displays back to enabled
+ private void resetLayoutLocked(int fromState, int toState, @DisplayPhase int phase) {
+ final Layout fromLayout = mDeviceStateToLayoutMap.get(fromState);
+ final Layout toLayout = mDeviceStateToLayoutMap.get(toState);
+
+ final int count = mLogicalDisplays.size();
+ for (int i = 0; i < count; i++) {
+ final LogicalDisplay logicalDisplay = mLogicalDisplays.valueAt(i);
+ final int displayId = logicalDisplay.getDisplayIdLocked();
+ final DisplayDevice device = logicalDisplay.getPrimaryDisplayDeviceLocked();
+ if (device == null) {
+ // If there's no device, then the logical display is due to be removed. Ignore it.
+ continue;
+ }
+
+ // Grab the display associations this display-device has in the old layout and the
+ // new layout.
+ final DisplayAddress address = device.getDisplayDeviceInfoLocked().address;
+
+ // Virtual displays do not have addresses.
+ final Layout.Display fromDisplay =
+ address != null ? fromLayout.getByAddress(address) : null;
+ final Layout.Display toDisplay =
+ address != null ? toLayout.getByAddress(address) : null;
+
+ // If a layout doesn't mention a display-device at all, then the display-device defaults
+ // to enabled. This is why we treat null as "enabled" in the code below.
+ final boolean wasEnabled = fromDisplay == null || fromDisplay.isEnabled();
+ final boolean willBeEnabled = toDisplay == null || toDisplay.isEnabled();
+
+ final boolean deviceHasNewLogicalDisplayId = fromDisplay != null && toDisplay != null
+ && fromDisplay.getLogicalDisplayId() != toDisplay.getLogicalDisplayId();
+
+ // We consider a display-device as changing/transition if
+ // 1) It's already marked as transitioning
+ // 2) It's going from enabled to disabled
+ // 3) It's enabled, but it's mapped to a new logical display ID. To the user this
+ // would look like apps moving from one screen to another since task-stacks stay
+ // with the logical display [ID].
+ final boolean isTransitioning =
+ (logicalDisplay.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION)
+ || (wasEnabled && !willBeEnabled)
+ || (wasEnabled && deviceHasNewLogicalDisplayId);
+
+ if (isTransitioning) {
+ setDisplayPhase(logicalDisplay, phase);
+ if (phase == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION) {
+ mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_TRANSITION);
+ }
}
}
}
-
/**
* Apply (or reapply) the currently selected display layout.
*/
private void applyLayoutLocked() {
- final Layout layout = mDeviceStateToLayoutMap.get(mDeviceState);
- mCurrentLayout = layout;
- Slog.i(TAG, "Applying the display layout for device state(" + mDeviceState
- + "): " + layout);
+ final Layout oldLayout = mCurrentLayout;
+ mCurrentLayout = mDeviceStateToLayoutMap.get(mDeviceState);
+ Slog.i(TAG, "Applying layout: " + mCurrentLayout + ", Previous layout: " + oldLayout);
// Go through each of the displays in the current layout set.
- final int size = layout.size();
+ final int size = mCurrentLayout.size();
for (int i = 0; i < size; i++) {
- final Layout.Display displayLayout = layout.getAt(i);
+ final Layout.Display displayLayout = mCurrentLayout.getAt(i);
// If the underlying display-device we want to use for this display
// doesn't exist, then skip it. This can happen at startup as display-devices
@@ -521,8 +669,12 @@
if (newDisplay != oldDisplay) {
newDisplay.swapDisplaysLocked(oldDisplay);
}
- enableDisplayLocked(newDisplay, displayLayout.isEnabled());
+
+ if (!displayLayout.isEnabled()) {
+ setDisplayPhase(newDisplay, LogicalDisplay.DISPLAY_PHASE_DISABLED);
+ }
}
+
}
@@ -540,23 +692,23 @@
final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
display.updateLocked(mDisplayDeviceRepo);
mLogicalDisplays.put(displayId, display);
- enableDisplayLocked(display, device != null);
+ setDisplayPhase(display, LogicalDisplay.DISPLAY_PHASE_ENABLED);
return display;
}
- private void enableDisplayLocked(LogicalDisplay display, boolean isEnabled) {
+ private void setDisplayPhase(LogicalDisplay display, @DisplayPhase int phase) {
final int displayId = display.getDisplayIdLocked();
final DisplayInfo info = display.getDisplayInfoLocked();
final boolean disallowSecondaryDisplay = mSingleDisplayDemoMode
&& (info.type != Display.TYPE_INTERNAL);
- if (isEnabled && disallowSecondaryDisplay) {
+ if (phase != LogicalDisplay.DISPLAY_PHASE_DISABLED && disallowSecondaryDisplay) {
Slog.i(TAG, "Not creating a logical display for a secondary display because single"
+ " display demo mode is enabled: " + display.getDisplayInfoLocked());
- isEnabled = false;
+ phase = LogicalDisplay.DISPLAY_PHASE_DISABLED;
}
- display.setEnabled(isEnabled);
+ display.setPhase(phase);
}
private int assignDisplayGroupIdLocked(boolean isOwnDisplayGroup) {
@@ -564,14 +716,15 @@
}
private void initializeInternalDisplayDeviceLocked(DisplayDevice device) {
- // We always want to make sure that our default display layout creates a logical
+ // We always want to make sure that our default layout creates a logical
// display for every internal display device that is found.
// To that end, when we are notified of a new internal display, we add it to
- // the default definition if it is not already there.
- final Layout layoutSet = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT);
+ // the default layout definition if it is not already there.
+ final Layout layout = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT);
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
final boolean isDefault = (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
- layoutSet.createDisplayLocked(info.address, isDefault, true /* isEnabled */);
+ final boolean isEnabled = isDefault || mSupportsConcurrentInternalDisplays;
+ layout.createDisplayLocked(info.address, isDefault, isEnabled);
}
private int assignLayerStackLocked(int displayId) {
@@ -580,9 +733,45 @@
return displayId;
}
+ private String displayEventToString(int msg) {
+ switch(msg) {
+ case LOGICAL_DISPLAY_EVENT_ADDED:
+ return "added";
+ case LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION:
+ return "transition";
+ case LOGICAL_DISPLAY_EVENT_CHANGED:
+ return "changed";
+ case LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED:
+ return "framerate_override";
+ case LOGICAL_DISPLAY_EVENT_SWAPPED:
+ return "swapped";
+ case LOGICAL_DISPLAY_EVENT_REMOVED:
+ return "removed";
+ }
+ return null;
+ }
+
public interface Listener {
void onLogicalDisplayEventLocked(LogicalDisplay display, int event);
void onDisplayGroupEventLocked(int groupId, int event);
void onTraversalRequested();
}
+
+ private class LogicalDisplayMapperHandler extends Handler {
+ LogicalDisplayMapperHandler(Looper looper) {
+ super(looper, null, true /*async*/);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_TRANSITION_TO_PENDING_DEVICE_STATE:
+ synchronized (mSyncRoot) {
+ finishStateTransitionLocked(true /*force*/);
+ }
+ break;
+ }
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/display/layout/Layout.java b/services/core/java/com/android/server/display/layout/Layout.java
index ef33667..e53aec1 100644
--- a/services/core/java/com/android/server/display/layout/Layout.java
+++ b/services/core/java/com/android/server/display/layout/Layout.java
@@ -19,6 +19,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.util.Slog;
import android.view.DisplayAddress;
@@ -100,11 +101,28 @@
*
* @return The display corresponding to the specified display ID.
*/
+ @Nullable
public Display getById(int id) {
for (int i = 0; i < mDisplays.size(); i++) {
- Display layout = mDisplays.get(i);
- if (id == layout.getLogicalDisplayId()) {
- return layout;
+ Display display = mDisplays.get(i);
+ if (id == display.getLogicalDisplayId()) {
+ return display;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param address The display address to check.
+ *
+ * @return The display corresponding to the specified address.
+ */
+ @Nullable
+ public Display getByAddress(@NonNull DisplayAddress address) {
+ for (int i = 0; i < mDisplays.size(); i++) {
+ Display display = mDisplays.get(i);
+ if (address.equals(display.getAddress())) {
+ return display;
}
}
return null;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index 2bf74c9..5802e53 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -232,7 +232,8 @@
DEST_DIRECT);
// Messages for Feature Discovery.
- addValidationInfo(Constants.MESSAGE_GIVE_FEATURES, noneValidator, DEST_DIRECT);
+ addValidationInfo(Constants.MESSAGE_GIVE_FEATURES, noneValidator,
+ DEST_DIRECT | SRC_UNREGISTERED);
addValidationInfo(Constants.MESSAGE_REPORT_FEATURES, new VariableLengthValidator(4, 14),
DEST_BROADCAST);
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 754fa25..77de187 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -422,6 +422,9 @@
// Set to true if the logical address allocation is completed.
private boolean mAddressAllocated = false;
+ // Whether a CEC-enabled sink is connected to the playback device
+ private boolean mIsCecAvailable = false;
+
// Object that handles logging statsd atoms.
// Use getAtomWriter() instead of accessing directly, to allow dependency injection for testing.
private HdmiCecAtomWriter mAtomWriter = new HdmiCecAtomWriter();
@@ -2229,6 +2232,7 @@
pw.println("mProhibitMode: " + mProhibitMode);
pw.println("mPowerStatus: " + mPowerStatusController.getPowerStatus());
+ pw.println("mIsCecAvailable: " + mIsCecAvailable);
pw.println("mCecVersion: " + mCecVersion);
// System settings
@@ -2450,7 +2454,7 @@
if (hdmiCecEnabled != HdmiControlManager.HDMI_CEC_CONTROL_ENABLED) {
return false;
}
- return true;
+ return mIsCecAvailable;
}
@ServiceThreadOnly
@@ -2835,24 +2839,24 @@
private void invokeHdmiControlStatusChangeListenerLocked(
Collection<IHdmiControlStatusChangeListener> listeners,
@HdmiControlManager.HdmiCecControl int isEnabled) {
- if (listeners.isEmpty()) {
- return;
- }
if (isEnabled == HdmiControlManager.HDMI_CEC_CONTROL_ENABLED) {
queryDisplayStatus(new IHdmiControlCallback.Stub() {
public void onComplete(int status) {
- boolean isAvailable = true;
if (status == HdmiControlManager.POWER_STATUS_UNKNOWN
|| status == HdmiControlManager.RESULT_EXCEPTION
|| status == HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE) {
- isAvailable = false;
+ mIsCecAvailable = false;
+ } else {
+ mIsCecAvailable = true;
}
- invokeHdmiControlStatusChangeListenerLocked(listeners, isEnabled, isAvailable);
}
});
- return;
+ } else {
+ mIsCecAvailable = false;
}
- invokeHdmiControlStatusChangeListenerLocked(listeners, isEnabled, false);
+ if (!listeners.isEmpty()) {
+ invokeHdmiControlStatusChangeListenerLocked(listeners, isEnabled, mIsCecAvailable);
+ }
}
private void invokeHdmiControlStatusChangeListenerLocked(
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 3424821..871b4f67 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3143,7 +3143,8 @@
@Override
public void showSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
- ResultReceiver resultReceiver, IBooleanResultCallback resultCallback) {
+ ResultReceiver resultReceiver, @SoftInputShowHideReason int reason,
+ IBooleanResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback, () -> {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showSoftInput");
int uid = Binder.getCallingUid();
@@ -3172,8 +3173,7 @@
}
}
if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
- return showCurrentInputLocked(windowToken, flags, resultReceiver,
- SoftInputShowHideReason.SHOW_SOFT_INPUT);
+ return showCurrentInputLocked(windowToken, flags, resultReceiver, reason);
} finally {
Binder.restoreCallingIdentity(ident);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -3262,7 +3262,8 @@
@Override
public void hideSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
- ResultReceiver resultReceiver, IBooleanResultCallback resultCallback) {
+ ResultReceiver resultReceiver, @SoftInputShowHideReason int reason,
+ IBooleanResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback, () -> {
int uid = Binder.getCallingUid();
ImeTracing.getInstance().triggerManagerServiceDump(
@@ -3296,8 +3297,7 @@
if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
return InputMethodManagerService.this.hideCurrentInputLocked(windowToken,
- flags, resultReceiver,
- SoftInputShowHideReason.HIDE_SOFT_INPUT);
+ flags, resultReceiver, reason);
} finally {
Binder.restoreCallingIdentity(ident);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -3326,8 +3326,8 @@
// since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only
// IMMS#InputShown indicates that the software keyboard is shown.
// TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
- final boolean shouldHideSoftInput = (mCurMethod != null) && (mInputShown ||
- (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
+ final boolean shouldHideSoftInput = (mCurMethod != null) && (mInputShown
+ || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
boolean res;
if (shouldHideSoftInput) {
final Binder hideInputToken = new Binder();
@@ -3355,68 +3355,100 @@
@NonNull
@Override
+ public void reportWindowGainedFocusAsync(
+ boolean nextFocusHasConnection, IInputMethodClient client, IBinder windowToken,
+ @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
+ int windowFlags, int unverifiedTargetSdkVersion) {
+ final int startInputReason = nextFocusHasConnection
+ ? StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION
+ : StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
+ try {
+ startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken,
+ startInputFlags, softInputMode, windowFlags, null /* attribute */,
+ null /* inputContext */, 0 /* missingMethods */, unverifiedTargetSdkVersion);
+ } catch (Throwable t) {
+ if (client != null) {
+ try {
+ client.throwExceptionFromSystem(t.getMessage());
+ } catch (RemoteException ignore) { }
+ }
+ }
+ }
+
+ @NonNull
+ @Override
public void startInputOrWindowGainedFocus(
@StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
@StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
@MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion,
IInputBindResultResultCallback resultCallback) {
- CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () -> {
- if (windowToken == null) {
- Slog.e(TAG, "windowToken cannot be null.");
+ CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () ->
+ startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken,
+ startInputFlags, softInputMode, windowFlags, attribute, inputContext,
+ missingMethods, unverifiedTargetSdkVersion));
+ }
+
+ @NonNull
+ private InputBindResult startInputOrWindowGainedFocusInternal(
+ @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
+ @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
+ int windowFlags, @Nullable EditorInfo attribute, @Nullable IInputContext inputContext,
+ @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) {
+ if (windowToken == null) {
+ Slog.e(TAG, "windowToken cannot be null.");
+ return InputBindResult.NULL;
+ }
+ try {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
+ "IMMS.startInputOrWindowGainedFocus");
+ ImeTracing.getInstance().triggerManagerServiceDump(
+ "InputMethodManagerService#startInputOrWindowGainedFocus");
+ final int callingUserId = UserHandle.getCallingUserId();
+ final int userId;
+ if (attribute != null && attribute.targetInputMethodUser != null
+ && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
+ mContext.enforceCallingPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "Using EditorInfo.targetInputMethodUser requires"
+ + " INTERACT_ACROSS_USERS_FULL.");
+ userId = attribute.targetInputMethodUser.getIdentifier();
+ if (!mUserManagerInternal.isUserRunning(userId)) {
+ // There is a chance that we hit here because of race condition. Let's just
+ // return an error code instead of crashing the caller process, which at
+ // least has INTERACT_ACROSS_USERS_FULL permission thus is likely to be an
+ // important process.
+ Slog.e(TAG, "User #" + userId + " is not running.");
+ return InputBindResult.INVALID_USER;
+ }
+ } else {
+ userId = callingUserId;
+ }
+ final InputBindResult result;
+ synchronized (mMethodMap) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ result = startInputOrWindowGainedFocusInternalLocked(startInputReason,
+ client, windowToken, startInputFlags, softInputMode, windowFlags,
+ attribute, inputContext, missingMethods, unverifiedTargetSdkVersion,
+ userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ if (result == null) {
+ // This must never happen, but just in case.
+ Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
+ + InputMethodDebug.startInputReasonToString(startInputReason)
+ + " windowFlags=#" + Integer.toHexString(windowFlags)
+ + " editorInfo=" + attribute);
return InputBindResult.NULL;
}
- try {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
- "IMMS.startInputOrWindowGainedFocus");
- ImeTracing.getInstance().triggerManagerServiceDump(
- "InputMethodManagerService#startInputOrWindowGainedFocus");
- final int callingUserId = UserHandle.getCallingUserId();
- final int userId;
- if (attribute != null && attribute.targetInputMethodUser != null
- && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
- mContext.enforceCallingPermission(
- Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "Using EditorInfo.targetInputMethodUser requires"
- + " INTERACT_ACROSS_USERS_FULL.");
- userId = attribute.targetInputMethodUser.getIdentifier();
- if (!mUserManagerInternal.isUserRunning(userId)) {
- // There is a chance that we hit here because of race condition. Let's just
- // return an error code instead of crashing the caller process, which at
- // least has INTERACT_ACROSS_USERS_FULL permission thus is likely to be an
- // important process.
- Slog.e(TAG, "User #" + userId + " is not running.");
- return InputBindResult.INVALID_USER;
- }
- } else {
- userId = callingUserId;
- }
- final InputBindResult result;
- synchronized (mMethodMap) {
- final long ident = Binder.clearCallingIdentity();
- try {
- result = startInputOrWindowGainedFocusInternalLocked(startInputReason,
- client, windowToken, startInputFlags, softInputMode, windowFlags,
- attribute, inputContext, missingMethods, unverifiedTargetSdkVersion,
- userId);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- if (result == null) {
- // This must never happen, but just in case.
- Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
- + InputMethodDebug.startInputReasonToString(startInputReason)
- + " windowFlags=#" + Integer.toHexString(windowFlags)
- + " editorInfo=" + attribute);
- return InputBindResult.NULL;
- }
- return result;
- } finally {
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
- });
+ return result;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
}
@NonNull
@@ -4444,7 +4476,7 @@
((IInputMethod) args.arg1).showSoftInput(
(IBinder) args.arg3, msg.arg1, (ResultReceiver) args.arg2);
mSoftInputShowHideHistory.addEntry(new SoftInputShowHideHistory.Entry(
- mCurClient, mCurAttribute,
+ mCurFocusedWindowClient, mCurAttribute,
mWindowManagerInternal.getWindowName(mCurFocusedWindow),
mCurFocusedWindowSoftInputMode, reason, mInFullscreenMode,
mWindowManagerInternal.getWindowName(
@@ -4467,7 +4499,7 @@
((IInputMethod)args.arg1).hideSoftInput(
(IBinder) args.arg3, 0, (ResultReceiver)args.arg2);
mSoftInputShowHideHistory.addEntry(new SoftInputShowHideHistory.Entry(
- mCurClient, mCurAttribute,
+ mCurFocusedWindowClient, mCurAttribute,
mWindowManagerInternal.getWindowName(mCurFocusedWindow),
mCurFocusedWindowSoftInputMode, reason, mInFullscreenMode,
mWindowManagerInternal.getWindowName(
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
index e25b03481..403187b 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
@@ -221,7 +221,6 @@
*/
@VisibleForTesting
public Context getSettingsContext(int displayId) {
- // TODO(b/178462039): Cover the case when IME is moved to another ImeContainer.
if (mSettingsContext == null || mSettingsContext.getDisplayId() != displayId) {
final Context systemUiContext = ActivityThread.currentActivityThread()
.createSystemUiContext(displayId);
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index fcaf6d8..69f293d 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1521,8 +1521,8 @@
@BinderThread
@Override
public void showSoftInput(
- IInputMethodClient client, IBinder token, int flags,
- ResultReceiver resultReceiver, IBooleanResultCallback resultCallback) {
+ IInputMethodClient client, IBinder token, int flags, ResultReceiver resultReceiver,
+ @SoftInputShowHideReason int reason, IBooleanResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback,
() -> showSoftInputInternal(client, token, flags, resultReceiver));
}
@@ -1577,7 +1577,8 @@
@Override
public void hideSoftInput(
IInputMethodClient client, IBinder windowToken, int flags,
- ResultReceiver resultReceiver, IBooleanResultCallback resultCallback) {
+ ResultReceiver resultReceiver, @SoftInputShowHideReason int reason,
+ IBooleanResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback,
() -> hideSoftInputInternal(client, windowToken, flags, resultReceiver));
@@ -1627,6 +1628,33 @@
@BinderThread
@Override
+ public void reportWindowGainedFocusAsync(
+ boolean nextFocusHasConnection,
+ @Nullable IInputMethodClient client,
+ @Nullable IBinder windowToken,
+ @StartInputFlags int startInputFlags,
+ @SoftInputModeFlags int softInputMode,
+ int windowFlags,
+ int unverifiedTargetSdkVersion) {
+ final int startInputReason = nextFocusHasConnection
+ ? StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION
+ : StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
+ try {
+ startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken,
+ startInputFlags, softInputMode, windowFlags, null /* editorInfo */,
+ null /* inputContext */, 0 /* missingMethods */,
+ unverifiedTargetSdkVersion);
+ } catch (Throwable t) {
+ if (client != null) {
+ try {
+ client.throwExceptionFromSystem(t.getMessage());
+ } catch (RemoteException ignore) { }
+ }
+ }
+ }
+
+ @BinderThread
+ @Override
public void startInputOrWindowGainedFocus(
@StartInputReason int startInputReason,
@Nullable IInputMethodClient client,
@@ -1641,8 +1669,8 @@
IInputBindResultResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () ->
startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken,
- startInputFlags, softInputMode, windowFlags, editorInfo, inputContext,
- missingMethods, unverifiedTargetSdkVersion));
+ startInputFlags, softInputMode, windowFlags, editorInfo, inputContext,
+ missingMethods, unverifiedTargetSdkVersion));
}
@BinderThread
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index d110839..ad5be07 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -30,6 +30,8 @@
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
+import static com.android.internal.widget.LockPatternUtils.PROFILE_KEY_NAME_DECRYPT;
+import static com.android.internal.widget.LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT;
import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
@@ -99,6 +101,7 @@
import android.security.keystore.recovery.KeyChainSnapshot;
import android.security.keystore.recovery.RecoveryCertPath;
import android.security.keystore.recovery.WrappedApplicationKey;
+import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
import android.security.keystore2.AndroidKeyStoreProvider;
import android.service.gatekeeper.GateKeeperResponse;
import android.service.gatekeeper.IGateKeeperService;
@@ -155,6 +158,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
+import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
@@ -226,6 +230,7 @@
private final SyntheticPasswordManager mSpManager;
private final KeyStore mKeyStore;
+ private final java.security.KeyStore mJavaKeyStore;
private final RecoverableKeyStoreManager mRecoverableKeyStoreManager;
private ManagedProfilePasswordCache mManagedProfilePasswordCache;
@@ -535,16 +540,22 @@
return Settings.Secure.getIntForUser(contentResolver, keyName, defaultValue, userId);
}
- public @NonNull ManagedProfilePasswordCache getManagedProfilePasswordCache() {
+ public java.security.KeyStore getJavaKeyStore() {
try {
java.security.KeyStore ks = java.security.KeyStore.getInstance(
SyntheticPasswordCrypto.androidKeystoreProviderName());
- ks.load(null);
- return new ManagedProfilePasswordCache(ks, getUserManager());
+ ks.load(new AndroidKeyStoreLoadStoreParameter(
+ SyntheticPasswordCrypto.keyNamespace()));
+ return ks;
} catch (Exception e) {
throw new IllegalStateException("Cannot load keystore", e);
}
}
+
+ public @NonNull ManagedProfilePasswordCache getManagedProfilePasswordCache(
+ java.security.KeyStore ks) {
+ return new ManagedProfilePasswordCache(ks, getUserManager());
+ }
}
public LockSettingsService(Context context) {
@@ -556,6 +567,7 @@
mInjector = injector;
mContext = injector.getContext();
mKeyStore = injector.getKeyStore();
+ mJavaKeyStore = injector.getJavaKeyStore();
mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager();
mHandler = injector.getHandler(injector.getServiceThread());
mStrongAuth = injector.getStrongAuth();
@@ -580,7 +592,7 @@
mRandom = new SecureRandom();
mSpManager = injector.getSyntheticPasswordManager(mStorage);
- mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache();
+ mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache(mJavaKeyStore);
mBiometricDeferredQueue = new BiometricDeferredQueue(mContext, mSpManager, mHandler);
mRebootEscrowManager = injector.getRebootEscrowManager(new RebootEscrowCallbacks(),
@@ -955,6 +967,21 @@
setString("migrated_wear_lockscreen_disabled", "true", 0);
Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices");
}
+
+ if (getString("migrated_keystore_namespace", null, 0) == null) {
+ boolean success = true;
+ synchronized (mSpManager) {
+ success &= mSpManager.migrateKeyNamespace();
+ }
+ success &= migrateProfileLockKeys();
+ if (success) {
+ setString("migrated_keystore_namespace", "true", 0);
+ Slog.i(TAG, "Migrated keys to LSS namespace");
+ } else {
+ Slog.w(TAG, "Failed to migrate keys to LSS namespace");
+ }
+ }
+
}
private void migrateOldDataAfterSystemReady() {
@@ -995,6 +1022,22 @@
}
}
+ private boolean migrateProfileLockKeys() {
+ boolean success = true;
+ final List<UserInfo> users = mUserManager.getUsers();
+ final int userCount = users.size();
+ for (int i = 0; i < userCount; i++) {
+ UserInfo user = users.get(i);
+ if (user.isManagedProfile() && !getSeparateProfileChallengeEnabledInternal(user.id)) {
+ success &= SyntheticPasswordCrypto.migrateLockSettingsKey(
+ PROFILE_KEY_NAME_ENCRYPT + user.id);
+ success &= SyntheticPasswordCrypto.migrateLockSettingsKey(
+ PROFILE_KEY_NAME_DECRYPT + user.id);
+ }
+ }
+ return success;
+ }
+
/**
* Returns the lowest password quality that still presents the same UI for entering it.
*
@@ -1286,11 +1329,8 @@
byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE,
storedData.length);
byte[] decryptionResult;
- java.security.KeyStore keyStore = java.security.KeyStore.getInstance(
- SyntheticPasswordCrypto.androidKeystoreProviderName());
- keyStore.load(null);
- SecretKey decryptionKey = (SecretKey) keyStore.getKey(
- LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null);
+ SecretKey decryptionKey = (SecretKey) mJavaKeyStore.getKey(
+ PROFILE_KEY_NAME_DECRYPT + userId, null);
Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE);
@@ -1880,30 +1920,26 @@
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
keyGenerator.init(new SecureRandom());
SecretKey secretKey = keyGenerator.generateKey();
- java.security.KeyStore keyStore = java.security.KeyStore.getInstance(
- SyntheticPasswordCrypto.androidKeystoreProviderName());
- keyStore.load(null);
try {
- keyStore.setEntry(
- LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId,
+ mJavaKeyStore.setEntry(
+ PROFILE_KEY_NAME_ENCRYPT + userId,
new java.security.KeyStore.SecretKeyEntry(secretKey),
new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
- keyStore.setEntry(
- LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId,
+ mJavaKeyStore.setEntry(
+ PROFILE_KEY_NAME_DECRYPT + userId,
new java.security.KeyStore.SecretKeyEntry(secretKey),
new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setUserAuthenticationRequired(true)
.setUserAuthenticationValidityDurationSeconds(30)
- .setCriticalToDeviceEncryption(true)
.build());
// Key imported, obtain a reference to it.
- SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey(
- LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null);
+ SecretKey keyStoreEncryptionKey = (SecretKey) mJavaKeyStore.getKey(
+ PROFILE_KEY_NAME_ENCRYPT + userId, null);
Cipher cipher = Cipher.getInstance(
KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
+ KeyProperties.ENCRYPTION_PADDING_NONE);
@@ -1912,10 +1948,10 @@
iv = cipher.getIV();
} finally {
// The original key can now be discarded.
- keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId);
+ mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_ENCRYPT + userId);
}
- } catch (CertificateException | UnrecoverableKeyException
- | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException
+ } catch (UnrecoverableKeyException
+ | BadPaddingException | IllegalBlockSizeException | KeyStoreException
| NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
throw new IllegalStateException("Failed to encrypt key", e);
}
@@ -2460,13 +2496,9 @@
private void removeKeystoreProfileKey(int targetUserId) {
Slog.i(TAG, "Remove keystore profile key for user: " + targetUserId);
try {
- java.security.KeyStore keyStore = java.security.KeyStore.getInstance(
- SyntheticPasswordCrypto.androidKeystoreProviderName());
- keyStore.load(null);
- keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId);
- keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId);
- } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
- | IOException e) {
+ mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_ENCRYPT + targetUserId);
+ mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_DECRYPT + targetUserId);
+ } catch (KeyStoreException e) {
// We have tried our best to remove all keys
Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e);
}
@@ -3420,6 +3452,12 @@
pw.println();
pw.decreaseIndent();
+ pw.println("Keys in namespace:");
+ pw.increaseIndent();
+ dumpKeystoreKeys(pw);
+ pw.println();
+ pw.decreaseIndent();
+
pw.println("Storage:");
pw.increaseIndent();
mStorage.dump(pw);
@@ -3441,6 +3479,18 @@
pw.println("PasswordHandleCount: " + mGatekeeperPasswords.size());
}
+ private void dumpKeystoreKeys(IndentingPrintWriter pw) {
+ try {
+ final Enumeration<String> aliases = mJavaKeyStore.aliases();
+ while (aliases.hasMoreElements()) {
+ pw.println(aliases.nextElement());
+ }
+ } catch (KeyStoreException e) {
+ pw.println("Unable to get keys: " + e.toString());
+ Slog.d(TAG, "Dump error", e);
+ }
+ }
+
/**
* Cryptographically disable escrow token support for the current user, if the user is not
* managed (either user has a profile owner, or if device is managed). Do not disable
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index 6a5c2d89..a73c8e0 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -311,7 +311,7 @@
PasswordMetrics metrics = new PasswordMetrics(
credential.isPattern() ? CREDENTIAL_TYPE_PATTERN : CREDENTIAL_TYPE_NONE);
errors = PasswordMetrics.validatePasswordMetrics(
- requiredMetrics, requiredComplexity, false /* isPin */, metrics);
+ requiredMetrics, requiredComplexity, metrics);
}
if (!errors.isEmpty()) {
getOutPrintWriter().println(
diff --git a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
index fa477c8..672c3f7 100644
--- a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
+++ b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
@@ -23,7 +23,6 @@
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.UserNotAuthenticatedException;
-import android.security.keystore2.AndroidKeyStoreSpi;
import android.util.Slog;
import android.util.SparseArray;
@@ -95,11 +94,12 @@
SecretKey key;
try {
generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,
- AndroidKeyStoreSpi.NAME);
+ mKeyStore.getProvider());
generator.init(new KeyGenParameterSpec.Builder(
keyName, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setKeySize(KEY_LENGTH)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setNamespace(SyntheticPasswordCrypto.keyNamespace())
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
// Generate auth-bound key to user 0 (since we the caller is user 0)
.setUserAuthenticationRequired(true)
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
index 35e6489..3386408 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
@@ -16,8 +16,12 @@
package com.android.server.locksettings;
+import android.security.AndroidKeyStoreMaintenance;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
+import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
import android.util.Slog;
import java.io.ByteArrayOutputStream;
@@ -125,9 +129,7 @@
public static byte[] decryptBlobV1(String keyAlias, byte[] blob, byte[] applicationId) {
try {
- KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName());
- keyStore.load(null);
-
+ KeyStore keyStore = getKeyStore();
SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null);
if (decryptionKey == null) {
throw new IllegalStateException("SP key is missing: " + keyAlias);
@@ -144,10 +146,20 @@
return "AndroidKeyStore";
}
+ static int keyNamespace() {
+ return KeyProperties.NAMESPACE_LOCKSETTINGS;
+ }
+
+ private static KeyStore getKeyStore()
+ throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
+ KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName());
+ keyStore.load(new AndroidKeyStoreLoadStoreParameter(keyNamespace()));
+ return keyStore;
+ }
+
public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] applicationId) {
try {
- KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName());
- keyStore.load(null);
+ final KeyStore keyStore = getKeyStore();
SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null);
if (decryptionKey == null) {
@@ -170,8 +182,7 @@
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
keyGenerator.init(AES_KEY_LENGTH * 8, new SecureRandom());
SecretKey secretKey = keyGenerator.generateKey();
- KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName());
- keyStore.load(null);
+ final KeyStore keyStore = getKeyStore();
KeyProtection.Builder builder = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
@@ -200,8 +211,7 @@
public static void destroyBlobKey(String keyAlias) {
KeyStore keyStore;
try {
- keyStore = KeyStore.getInstance(androidKeystoreProviderName());
- keyStore.load(null);
+ keyStore = getKeyStore();
keyStore.deleteEntry(keyAlias);
Slog.i(TAG, "SP key deleted: " + keyAlias);
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
@@ -229,4 +239,32 @@
throw new IllegalStateException("NoSuchAlgorithmException for SHA-512", e);
}
}
+
+ static boolean migrateLockSettingsKey(String alias) {
+ final KeyDescriptor legacyKey = new KeyDescriptor();
+ legacyKey.domain = Domain.APP;
+ legacyKey.nspace = KeyProperties.NAMESPACE_APPLICATION;
+ legacyKey.alias = alias;
+
+ final KeyDescriptor newKey = new KeyDescriptor();
+ newKey.domain = Domain.SELINUX;
+ newKey.nspace = SyntheticPasswordCrypto.keyNamespace();
+ newKey.alias = alias;
+ Slog.i(TAG, "Migrating key " + alias);
+ int err = AndroidKeyStoreMaintenance.migrateKeyNamespace(legacyKey, newKey);
+ if (err == 0) {
+ return true;
+ } else if (err == AndroidKeyStoreMaintenance.KEY_NOT_FOUND) {
+ Slog.i(TAG, "Key does not exist");
+ // Treat this as a success so we don't migrate again.
+ return true;
+ } else if (err == AndroidKeyStoreMaintenance.INVALID_ARGUMENT) {
+ Slog.i(TAG, "Key already exists");
+ // Treat this as a success so we don't migrate again.
+ return true;
+ } else {
+ Slog.e(TAG, String.format("Failed to migrate key: %d", err));
+ return false;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index a5763ae..601a572 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -522,7 +522,7 @@
public void removeUser(int userId) {
for (long handle : mStorage.listSyntheticPasswordHandlesForUser(SP_BLOB_NAME, userId)) {
destroyWeaverSlot(handle, userId);
- destroySPBlobKey(getHandleName(handle));
+ destroySPBlobKey(getKeyName(handle));
}
}
@@ -958,7 +958,7 @@
} else {
secret = authToken.getSyntheticPassword();
}
- byte[] content = createSPBlob(getHandleName(handle), secret, applicationId, sid);
+ byte[] content = createSPBlob(getKeyName(handle), secret, applicationId, sid);
byte[] blob = new byte[content.length + 1 + 1];
/*
* We can upgrade from v1 to v2 because that's just a change in the way that
@@ -1141,10 +1141,10 @@
}
final byte[] secret;
if (version == SYNTHETIC_PASSWORD_VERSION_V1) {
- secret = SyntheticPasswordCrypto.decryptBlobV1(getHandleName(handle),
+ secret = SyntheticPasswordCrypto.decryptBlobV1(getKeyName(handle),
Arrays.copyOfRange(blob, 2, blob.length), applicationId);
} else {
- secret = decryptSPBlob(getHandleName(handle),
+ secret = decryptSPBlob(getKeyName(handle),
Arrays.copyOfRange(blob, 2, blob.length), applicationId);
}
if (secret == null) {
@@ -1247,7 +1247,7 @@
private void destroySyntheticPassword(long handle, int userId) {
destroyState(SP_BLOB_NAME, handle, userId);
- destroySPBlobKey(getHandleName(handle));
+ destroySPBlobKey(getKeyName(handle));
if (hasState(WEAVER_SLOT_NAME, handle, userId)) {
destroyWeaverSlot(handle, userId);
}
@@ -1363,7 +1363,7 @@
}
}
- private String getHandleName(long handle) {
+ private String getKeyName(long handle) {
return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, handle);
}
@@ -1424,4 +1424,19 @@
}
return hexBytes;
}
+
+ /**
+ * Migrate all existing SP keystore keys from uid 1000 app domain to LSS selinux domain
+ */
+ public boolean migrateKeyNamespace() {
+ boolean success = true;
+ final Map<Integer, List<Long>> allHandles =
+ mStorage.listSyntheticPasswordHandlesForAllUsers(SP_BLOB_NAME);
+ for (List<Long> userHandles : allHandles.values()) {
+ for (long handle : userHandles) {
+ success &= SyntheticPasswordCrypto.migrateLockSettingsKey(getKeyName(handle));
+ }
+ }
+ return success;
+ }
}
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index 29b5e81..78219bc 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -147,15 +147,16 @@
}
private boolean isImportantOngoing(NotificationRecord record) {
- if (!isOngoing(record)) {
- return false;
- }
-
if (record.getImportance() < NotificationManager.IMPORTANCE_LOW) {
return false;
}
-
- return isCall(record) || isMediaNotification(record);
+ if (isCallStyle(record)) {
+ return true;
+ }
+ if (!isOngoing(record)) {
+ return false;
+ }
+ return isCallCategory(record) || isMediaNotification(record);
}
protected boolean isImportantPeople(NotificationRecord record) {
@@ -181,11 +182,16 @@
return record.getNotification().hasMediaSession();
}
- private boolean isCall(NotificationRecord record) {
+ private boolean isCallCategory(NotificationRecord record) {
return record.isCategory(Notification.CATEGORY_CALL)
&& isDefaultPhoneApp(record.getSbn().getPackageName());
}
+ private boolean isCallStyle(NotificationRecord record) {
+ return "android.app.Notification$CallStyle".equals(
+ record.getNotification().extras.getString(Notification.EXTRA_TEMPLATE));
+ }
+
private boolean isDefaultPhoneApp(String pkg) {
if (mDefaultPhoneApp == null) {
final TelecomManager telecomm =
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1c50d41..215c393 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -695,14 +695,15 @@
// Remove notifications with the specified user & channel ID.
public void removeChannelNotifications(String pkg, @UserIdInt int userId,
String channelId) {
- for (int i = 0; i < mBuffer.size(); i++) {
- final Pair<StatusBarNotification, Integer> pair = mBuffer.get(i);
+ Iterator<Pair<StatusBarNotification, Integer>> bufferIter = mBuffer.iterator();
+ while (bufferIter.hasNext()) {
+ final Pair<StatusBarNotification, Integer> pair = bufferIter.next();
if (pair.first != null
&& userId == pair.first.getNormalizedUserId()
&& pkg != null && pkg.equals(pair.first.getPackageName())
&& pair.first.getNotification() != null
&& Objects.equals(channelId, pair.first.getNotification().getChannelId())) {
- mBuffer.remove(i);
+ bufferIter.remove();
}
}
}
@@ -6570,6 +6571,17 @@
}
}
+ if ("android.app.Notification$CallStyle".equals(
+ n.extras.getString(Notification.EXTRA_TEMPLATE))) {
+ boolean isForegroundService = (n.flags & FLAG_FOREGROUND_SERVICE) != 0;
+ boolean hasFullScreenIntent = n.fullScreenIntent != null;
+ if (!isForegroundService && !hasFullScreenIntent) {
+ throw new IllegalArgumentException(r.getKey() + " Not posted."
+ + " CallStyle notifications must either be for a foreground Service or"
+ + " use a fullScreenIntent.");
+ }
+ }
+
// snoozed apps
if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
MetricsLogger.action(r.getLogMaker()
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 4f527f2..cd352b5 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -35,6 +35,7 @@
import android.content.pm.parsing.component.ParsedIntentInfo;
import android.content.pm.parsing.component.ParsedMainComponent;
import android.content.pm.parsing.component.ParsedProvider;
+import android.os.Binder;
import android.os.Process;
import android.os.Trace;
import android.os.UserHandle;
@@ -51,6 +52,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.function.QuadFunction;
import com.android.server.FgThread;
import com.android.server.compat.CompatChange;
import com.android.server.om.OverlayReferenceMapper;
@@ -69,7 +71,6 @@
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.Executor;
-import java.util.function.Function;
/**
* The entity responsible for filtering visibility between apps based on declarations in their
@@ -1447,14 +1448,20 @@
public void dumpQueries(
PrintWriter pw, @Nullable Integer filteringAppId, DumpState dumpState, int[] users,
- Function<Integer, String[]> getPackagesForUid) {
+ QuadFunction<Integer, Integer, Integer, Boolean, String[]> getPackagesForUid) {
final SparseArray<String> cache = new SparseArray<>();
ToString<Integer> expandPackages = input -> {
String cachedValue = cache.get(input);
if (cachedValue == null) {
- final String[] packagesForUid = getPackagesForUid.apply(input);
+ final int callingUid = Binder.getCallingUid();
+ final int appId = UserHandle.getAppId(input);
+ String[] packagesForUid = null;
+ for (int i = 0, size = users.length; packagesForUid == null && i < size; i++) {
+ packagesForUid = getPackagesForUid.apply(callingUid, users[i], appId,
+ false /*isCallerInstantApp*/);
+ }
if (packagesForUid == null) {
- cachedValue = "[unknown app id " + input + "]";
+ cachedValue = "[app id " + input + " not installed]";
} else {
cachedValue = packagesForUid.length == 1 ? packagesForUid[0]
: "[" + TextUtils.join(",", packagesForUid) + "]";
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 6b7e729..bf114d8 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -883,6 +883,14 @@
return isDataLoaderInstallation() && params.dataLoaderParams.getType() == INCREMENTAL;
}
+ private boolean isSystemDataLoaderInstallation() {
+ if (!isDataLoaderInstallation()) {
+ return false;
+ }
+ return SYSTEM_DATA_LOADER_PACKAGE.equals(
+ this.params.dataLoaderParams.getComponentName().getPackageName());
+ }
+
/**
* @return {@code true} iff the installing is app an device owner or affiliated profile owner.
*/
@@ -1058,9 +1066,7 @@
"DataLoader installation of APEX modules is not allowed.");
}
- boolean systemDataLoader = SYSTEM_DATA_LOADER_PACKAGE.equals(
- this.params.dataLoaderParams.getComponentName().getPackageName());
- if (systemDataLoader && mContext.checkCallingOrSelfPermission(
+ if (isSystemDataLoaderInstallation() && mContext.checkCallingOrSelfPermission(
Manifest.permission.USE_SYSTEM_DATA_LOADERS)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("You need the "
@@ -2107,6 +2113,23 @@
dispatchSessionFinished(error, detailedMessage, null);
}
+ private void onSystemDataLoaderUnrecoverable() {
+ final PackageManagerService packageManagerService = mPm;
+ final String packageName = mPackageName;
+ if (TextUtils.isEmpty(packageName)) {
+ // The package has not been installed.
+ return;
+ }
+ mHandler.post(() -> {
+ if (packageManagerService.deletePackageX(packageName,
+ PackageManager.VERSION_CODE_HIGHEST, UserHandle.USER_SYSTEM,
+ PackageManager.DELETE_ALL_USERS, true /*removedBySystem*/)
+ != PackageManager.DELETE_SUCCEEDED) {
+ Slog.e(TAG, "Failed to uninstall package with failed dataloader: " + packageName);
+ }
+ });
+ }
+
/**
* If session should be sealed, then it's sealed to prevent further modification.
* If the session can't be sealed then it's destroyed.
@@ -3740,6 +3763,7 @@
final DataLoaderParams params = this.params.dataLoaderParams;
final boolean manualStartAndDestroy = !isIncrementalInstallation();
+ final boolean systemDataLoader = isSystemDataLoaderInstallation();
final IDataLoaderStatusListener statusListener = new IDataLoaderStatusListener.Stub() {
@Override
public void onStatusChanged(int dataLoaderId, int status) {
@@ -3751,10 +3775,15 @@
}
if (mDestroyed || mDataLoaderFinished) {
- // No need to worry about post installation
+ switch (status) {
+ case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
+ if (systemDataLoader) {
+ onSystemDataLoaderUnrecoverable();
+ }
+ return;
+ }
return;
}
-
try {
IDataLoader dataLoader = dataLoaderManager.getDataLoader(dataLoaderId);
if (dataLoader == null) {
@@ -3848,14 +3877,18 @@
healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
healthCheckParams.unhealthyMonitoringMs = INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
- final boolean systemDataLoader = SYSTEM_DATA_LOADER_PACKAGE.equals(
- params.getComponentName().getPackageName());
-
final IStorageHealthListener healthListener = new IStorageHealthListener.Stub() {
@Override
public void onHealthStatus(int storageId, int status) {
if (mDestroyed || mDataLoaderFinished) {
- // No need to worry about post installation
+ // App's installed.
+ switch (status) {
+ case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY:
+ if (systemDataLoader) {
+ onSystemDataLoaderUnrecoverable();
+ }
+ return;
+ }
return;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d2cbcf0..8d6c145 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4619,7 +4619,7 @@
Integer filteringAppId = setting == null ? null : setting.appId;
mAppsFilter.dumpQueries(
pw, filteringAppId, dumpState, mUserManager.getUserIds(),
- this::getPackagesForUid);
+ this::getPackagesForUidInternalBody);
break;
}
@@ -21627,7 +21627,8 @@
null /*disabledComponents*/,
PackageManager.INSTALL_REASON_UNKNOWN,
PackageManager.UNINSTALL_REASON_UNKNOWN,
- null /*harmfulAppWarning*/);
+ null /*harmfulAppWarning*/,
+ null /*splashScreenTheme*/);
}
mSettings.writeKernelMappingLPr(ps);
}
@@ -27701,6 +27702,23 @@
return mSettings.getPackageLPr(packageName).getMimeGroup(mimeGroup);
}
+ @Override
+ public void setSplashScreenTheme(@NonNull String packageName, @Nullable String themeId,
+ int userId) {
+ int callingUid = Binder.getCallingUid();
+ PackageSetting packageSetting = getPackageSettingForUser(packageName, callingUid, userId);
+ if (packageSetting != null) {
+ packageSetting.setSplashScreenTheme(userId, themeId);
+ }
+ }
+
+ @Override
+ public String getSplashScreenTheme(@NonNull String packageName, int userId) {
+ int callingUid = Binder.getCallingUid();
+ PackageSetting packageSetting = getPackageSettingForUser(packageName, callingUid, userId);
+ return packageSetting != null ? packageSetting.getSplashScreenTheme(userId) : null;
+ }
+
/**
* Temporary method that wraps mSettings.writeLPr() and calls mPermissionManager's
* writeLegacyPermissionsTEMP() beforehand.
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 19b56b7..731d41c 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -493,7 +493,8 @@
ArrayMap<String, PackageUserState.SuspendParams> suspendParams, boolean instantApp,
boolean virtualPreload, String lastDisableAppCaller,
ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
- int installReason, int uninstallReason, String harmfulAppWarning) {
+ int installReason, int uninstallReason, String harmfulAppWarning,
+ String splashScreenTheme) {
PackageUserState state = modifyUserState(userId);
state.ceDataInode = ceDataInode;
state.enabled = enabled;
@@ -512,6 +513,7 @@
state.instantApp = instantApp;
state.virtualPreload = virtualPreload;
state.harmfulAppWarning = harmfulAppWarning;
+ state.splashScreenTheme = splashScreenTheme;
onChanged();
}
@@ -522,7 +524,8 @@
otherState.instantApp,
otherState.virtualPreload, otherState.lastDisableAppCaller,
otherState.enabledComponents, otherState.disabledComponents,
- otherState.installReason, otherState.uninstallReason, otherState.harmfulAppWarning);
+ otherState.installReason, otherState.uninstallReason, otherState.harmfulAppWarning,
+ otherState.splashScreenTheme);
}
ArraySet<String> getEnabledComponents(int userId) {
@@ -723,6 +726,26 @@
}
/**
+ * @param userId the specified user to modify the theme for
+ * @param themeName the theme name to persist
+ * @see android.window.SplashScreen#setSplashScreenTheme(int)
+ */
+ public void setSplashScreenTheme(@UserIdInt int userId, @Nullable String themeName) {
+ modifyUserState(userId).splashScreenTheme = themeName;
+ }
+
+ /**
+ * @param userId the specified user to get the theme setting from
+ * @return the theme name previously persisted for the user or null
+ * if no splashscreen theme is persisted.
+ * @see android.window.SplashScreen#setSplashScreenTheme(int)
+ */
+ @Nullable
+ public String getSplashScreenTheme(@UserIdInt int userId) {
+ return readUserState(userId).splashScreenTheme;
+ }
+
+ /**
* @return True if package is still being loaded, false if the package is fully loaded.
*/
public boolean isPackageLoading() {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index e409019..b6d4a5b 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -340,6 +340,7 @@
private static final String ATTR_INSTANT_APP = "instant-app";
private static final String ATTR_VIRTUAL_PRELOAD = "virtual-preload";
private static final String ATTR_HARMFUL_APP_WARNING = "harmful-app-warning";
+ private static final String ATTR_SPLASH_SCREEN_THEME = "splash-screen-theme";
private static final String ATTR_PACKAGE_NAME = "packageName";
private static final String ATTR_FINGERPRINT = "fingerprint";
@@ -939,7 +940,9 @@
null /*disabledComponents*/,
PackageManager.INSTALL_REASON_UNKNOWN,
PackageManager.UNINSTALL_REASON_UNKNOWN,
- null /*harmfulAppWarning*/);
+ null, /*harmfulAppWarning*/
+ null /*splashscreenTheme*/
+ );
}
}
}
@@ -1578,7 +1581,8 @@
null /*disabledComponents*/,
PackageManager.INSTALL_REASON_UNKNOWN,
PackageManager.UNINSTALL_REASON_UNKNOWN,
- null /*harmfulAppWarning*/);
+ null /*harmfulAppWarning*/,
+ null /* splashScreenTheme*/);
}
return;
}
@@ -1666,6 +1670,8 @@
PackageManager.INSTALL_REASON_UNKNOWN);
final int uninstallReason = parser.getAttributeInt(null, ATTR_UNINSTALL_REASON,
PackageManager.UNINSTALL_REASON_UNKNOWN);
+ final String splashScreenTheme = parser.getAttributeValue(null,
+ ATTR_SPLASH_SCREEN_THEME);
ArraySet<String> enabledComponents = null;
ArraySet<String> disabledComponents = null;
@@ -1738,7 +1744,8 @@
ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
hidden, distractionFlags, suspended, suspendParamsMap,
instantApp, virtualPreload, enabledCaller, enabledComponents,
- disabledComponents, installReason, uninstallReason, harmfulAppWarning);
+ disabledComponents, installReason, uninstallReason, harmfulAppWarning,
+ splashScreenTheme);
mDomainVerificationManager.setLegacyUserState(name, userId, verifState);
} else if (tagName.equals("preferred-activities")) {
@@ -1995,6 +2002,10 @@
serializer.attribute(null, ATTR_HARMFUL_APP_WARNING,
ustate.harmfulAppWarning);
}
+ if (ustate.splashScreenTheme != null) {
+ serializer.attribute(null, ATTR_SPLASH_SCREEN_THEME,
+ ustate.splashScreenTheme);
+ }
if (ustate.suspended) {
for (int i = 0; i < ustate.suspendParams.size(); i++) {
final String suspendingPackage = ustate.suspendParams.keyAt(i);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 007393a..678f046 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1992,10 +1992,11 @@
packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
verifyStates();
+
+ ret.complete(true);
} catch (Exception e) {
ret.completeExceptionally(e);
}
- ret.complete(true);
});
return ret;
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 1e92ca6..50f958f 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -211,6 +211,7 @@
NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_ADVERTISE);
NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_CONNECT);
NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_SCAN);
+ NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.UWB_RANGING);
}
private static final int MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS = 1;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
index a8a6a72..a5ba82f 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
@@ -17,6 +17,7 @@
package com.android.server.pm.verify.domain;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.Intent;
@@ -33,6 +34,8 @@
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.util.List;
+import java.util.Objects;
+import java.util.function.BiFunction;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -44,6 +47,12 @@
private static final int MAX_DOMAINS_BYTE_SIZE = 1024 * 1024;
+ private static final BiFunction<ArraySet<String>, String, Boolean> ARRAY_SET_COLLECTOR =
+ (set, domain) -> {
+ set.add(domain);
+ return null;
+ };
+
@NonNull
private final PlatformCompat mPlatformCompat;
@@ -105,27 +114,62 @@
return collectDomains(pkg, true /* checkAutoVerify */, false /* valid */);
}
+ public boolean containsWebDomain(@NonNull AndroidPackage pkg, @NonNull String targetDomain) {
+ return collectDomains(pkg, false /* checkAutoVerify */, true /* valid */, null,
+ (BiFunction<Void, String, Boolean>) (unused, domain) -> {
+ if (Objects.equals(targetDomain, domain)) {
+ return true;
+ }
+ return null;
+ }) != null;
+ }
+
+ public boolean containsAutoVerifyDomain(@NonNull AndroidPackage pkg,
+ @NonNull String targetDomain) {
+ return collectDomains(pkg, true /* checkAutoVerify */, true /* valid */, null,
+ (BiFunction<Void, String, Boolean>) (unused, domain) -> {
+ if (Objects.equals(targetDomain, domain)) {
+ return true;
+ }
+ return null;
+ }) != null;
+ }
+
@NonNull
private ArraySet<String> collectDomains(@NonNull AndroidPackage pkg,
boolean checkAutoVerify, boolean valid) {
+ ArraySet<String> domains = new ArraySet<>();
+ collectDomains(pkg, checkAutoVerify, valid, domains, ARRAY_SET_COLLECTOR);
+ return domains;
+ }
+
+ @NonNull
+ private <InitialValue, ReturnValue> ReturnValue collectDomains(@NonNull AndroidPackage pkg,
+ boolean checkAutoVerify, boolean valid, @Nullable InitialValue initialValue,
+ @NonNull BiFunction<InitialValue, String, ReturnValue> domainCollector) {
boolean restrictDomains =
DomainVerificationUtils.isChangeEnabled(mPlatformCompat, pkg, RESTRICT_DOMAINS);
if (restrictDomains) {
- return collectDomainsInternal(pkg, checkAutoVerify, valid);
+ return collectDomainsInternal(pkg, checkAutoVerify, valid, initialValue,
+ domainCollector);
} else {
- return collectDomainsLegacy(pkg, checkAutoVerify, valid);
+ return collectDomainsLegacy(pkg, checkAutoVerify, valid, initialValue, domainCollector);
}
}
/**
* @see #RESTRICT_DOMAINS
*/
- private ArraySet<String> collectDomainsLegacy(@NonNull AndroidPackage pkg,
- boolean checkAutoVerify, boolean valid) {
+ @Nullable
+ private <InitialValue, ReturnValue> ReturnValue collectDomainsLegacy(
+ @NonNull AndroidPackage pkg, boolean checkAutoVerify, boolean valid,
+ @Nullable InitialValue initialValue,
+ @NonNull BiFunction<InitialValue, String, ReturnValue> domainCollector) {
if (!checkAutoVerify) {
// Per-domain user selection state doesn't have a V1 equivalent on S, so just use V2
- return collectDomainsInternal(pkg, false /* checkAutoVerify */, true /* valid */);
+ return collectDomainsInternal(pkg, false /* checkAutoVerify */, true /* valid */,
+ initialValue, domainCollector);
}
List<ParsedActivity> activities = pkg.getActivities();
@@ -148,11 +192,10 @@
}
if (!needsAutoVerify) {
- return new ArraySet<>();
+ return null;
}
}
- ArraySet<String> domains = new ArraySet<>();
int totalSize = 0;
boolean underMaxSize = true;
for (int activityIndex = 0; activityIndex < activitiesSize && underMaxSize;
@@ -169,22 +212,30 @@
if (isValidHost(host) == valid) {
totalSize += byteSizeOf(host);
underMaxSize = totalSize < MAX_DOMAINS_BYTE_SIZE;
- domains.add(host);
+ ReturnValue returnValue = domainCollector.apply(initialValue, host);
+ if (returnValue != null) {
+ return returnValue;
+ }
}
}
}
}
}
- return domains;
+ return null;
}
/**
* @see #RESTRICT_DOMAINS
+ * @param domainCollector Function to call with initialValue and a valid host. Should return
+ * a non-null value if the function should return immediately
+ * after the currently processed host.
*/
- private ArraySet<String> collectDomainsInternal(@NonNull AndroidPackage pkg,
- boolean checkAutoVerify, boolean valid) {
- ArraySet<String> domains = new ArraySet<>();
+ @Nullable
+ private <InitialValue, ReturnValue> ReturnValue collectDomainsInternal(
+ @NonNull AndroidPackage pkg, boolean checkAutoVerify, boolean valid,
+ @Nullable InitialValue initialValue,
+ @NonNull BiFunction<InitialValue, String, ReturnValue> domainCollector) {
int totalSize = 0;
boolean underMaxSize = true;
@@ -226,13 +277,16 @@
if (isValidHost(host) == valid) {
totalSize += byteSizeOf(host);
underMaxSize = totalSize < MAX_DOMAINS_BYTE_SIZE;
- domains.add(host);
+ ReturnValue returnValue = domainCollector.apply(initialValue, host);
+ if (returnValue != null) {
+ return returnValue;
+ }
}
}
}
}
- return domains;
+ return null;
}
/**
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
index 1d04478..adf8f0d 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
@@ -37,6 +37,7 @@
import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
import java.util.Arrays;
+import java.util.List;
import java.util.function.Function;
@SuppressWarnings("PointlessBooleanExpression")
@@ -100,6 +101,70 @@
}
}
+ /**
+ * @param userIdToApprovalLevelToOwners Mapping of user ID to approval level to domain owners.
+ */
+ public void printOwners(@NonNull IndentingPrintWriter writer, @NonNull String domain,
+ SparseArray<SparseArray<List<String>>> userIdToApprovalLevelToOwners) {
+ writer.println(domain + ":");
+ writer.increaseIndent();
+
+ if (userIdToApprovalLevelToOwners.size() == 0) {
+ writer.println("none");
+ writer.decreaseIndent();
+ return;
+ }
+
+ int usersSize = userIdToApprovalLevelToOwners.size();
+ for (int userIndex = 0; userIndex < usersSize; userIndex++) {
+ int userId = userIdToApprovalLevelToOwners.keyAt(userIndex);
+ SparseArray<List<String>> approvalLevelToOwners =
+ userIdToApprovalLevelToOwners.valueAt(userIndex);
+
+ if (approvalLevelToOwners.size() == 0) {
+ continue;
+ }
+
+ boolean printedUserHeader = false;
+ int approvalsSize = approvalLevelToOwners.size();
+ for (int approvalIndex = 0; approvalIndex < approvalsSize; approvalIndex++) {
+ int approvalLevel = approvalLevelToOwners.keyAt(approvalIndex);
+ if (approvalLevel < DomainVerificationManagerInternal.APPROVAL_LEVEL_UNVERIFIED) {
+ continue;
+ }
+
+ if (!printedUserHeader) {
+ writer.println("User " + userId + ":");
+ writer.increaseIndent();
+ printedUserHeader = true;
+ }
+
+ String approvalString =
+ DomainVerificationManagerInternal.approvalLevelToDebugString(approvalLevel);
+ List<String> owners = approvalLevelToOwners.valueAt(approvalIndex);
+ writer.println(approvalString + "[" + approvalLevel + "]" + ":");
+ writer.increaseIndent();
+
+ if (owners.size() == 0) {
+ writer.println("none");
+ writer.decreaseIndent();
+ continue;
+ }
+
+ int ownersSize = owners.size();
+ for (int ownersIndex = 0; ownersIndex < ownersSize; ownersIndex++) {
+ writer.println(owners.get(ownersIndex));
+ }
+ writer.decreaseIndent();
+ }
+
+ if (printedUserHeader) {
+ writer.decreaseIndent();
+ }
+ }
+ writer.decreaseIndent();
+ }
+
boolean printState(@NonNull IndentingPrintWriter writer,
@NonNull DomainVerificationPkgState pkgState, @NonNull AndroidPackage pkg,
@NonNull ArrayMap<String, Integer> reusedMap, boolean wasHeaderPrinted) {
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
index 0f99e19..5aed367 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
@@ -57,6 +57,28 @@
UUID DISABLED_ID = new UUID(0, 0);
/**
+ * The app was not installed for the user.
+ */
+ int APPROVAL_LEVEL_NOT_INSTALLED = -4;
+
+ /**
+ * The app was not enabled for the user.
+ */
+ int APPROVAL_LEVEL_DISABLED = -3;
+
+ /**
+ * The app has not declared this domain in a valid web intent-filter in their manifest, and so
+ * would never be able to be approved for this domain.
+ */
+ int APPROVAL_LEVEL_UNDECLARED = -2;
+
+ /**
+ * The app has declared this domain as a valid autoVerify domain, but it failed or has not
+ * succeeded verification.
+ */
+ int APPROVAL_LEVEL_UNVERIFIED = -1;
+
+ /**
* The app has not been approved for this domain and should never be able to open it through
* an implicit web intent.
*/
@@ -117,10 +139,14 @@
* by approval priority. A higher numerical value means the package should override all lower
* values. This means that comparison using less/greater than IS valid.
*
- * Negative values are possible, although not implemented, reserved if explicit disable of a
- * package for a domain needs to be tracked.
+ * Negative values are possible, used for tracking specific reasons for why an app doesn't have
+ * approval.
*/
@IntDef({
+ APPROVAL_LEVEL_NOT_INSTALLED,
+ APPROVAL_LEVEL_DISABLED,
+ APPROVAL_LEVEL_UNDECLARED,
+ APPROVAL_LEVEL_UNVERIFIED,
APPROVAL_LEVEL_NONE,
APPROVAL_LEVEL_LEGACY_ASK,
APPROVAL_LEVEL_LEGACY_ALWAYS,
@@ -131,6 +157,33 @@
@interface ApprovalLevel {
}
+ static String approvalLevelToDebugString(@ApprovalLevel int level) {
+ switch (level) {
+ case APPROVAL_LEVEL_NOT_INSTALLED:
+ return "NOT_INSTALLED";
+ case APPROVAL_LEVEL_DISABLED:
+ return "DISABLED";
+ case APPROVAL_LEVEL_UNDECLARED:
+ return "UNDECLARED";
+ case APPROVAL_LEVEL_UNVERIFIED:
+ return "UNVERIFIED";
+ case APPROVAL_LEVEL_NONE:
+ return "NONE";
+ case APPROVAL_LEVEL_LEGACY_ASK:
+ return "LEGACY_ASK";
+ case APPROVAL_LEVEL_LEGACY_ALWAYS:
+ return "LEGACY_ALWAYS";
+ case APPROVAL_LEVEL_SELECTION:
+ return "USER_SELECTION";
+ case APPROVAL_LEVEL_VERIFIED:
+ return "VERIFIED";
+ case APPROVAL_LEVEL_INSTANT_APP:
+ return "INSTANT_APP";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
/** @see DomainVerificationManager#getDomainVerificationInfo(String) */
@Nullable
@RequiresPermission(anyOf = {
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index a3e1a9c..3a4b849 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -741,62 +741,21 @@
});
}
+ @NonNull
public List<DomainOwner> getOwnersForDomain(@NonNull String domain, @UserIdInt int userId) {
Objects.requireNonNull(domain);
mEnforcer.assertOwnerQuerent(mConnection.getCallingUid(), mConnection.getCallingUserId(),
userId);
- SparseArray<List<String>> levelToPackages = new SparseArray<>();
return mConnection.withPackageSettingsReturningThrowing(pkgSettings -> {
- // First, collect the raw approval level values
- synchronized (mLock) {
- final int size = mAttachedPkgStates.size();
- for (int index = 0; index < size; index++) {
- DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
- String packageName = pkgState.getPackageName();
- PackageSetting pkgSetting = pkgSettings.apply(packageName);
- if (pkgSetting == null) {
- continue;
- }
-
- int level = approvalLevelForDomain(pkgSetting, domain, userId, domain);
- if (level <= APPROVAL_LEVEL_NONE) {
- continue;
- }
- List<String> list = levelToPackages.get(level);
- if (list == null) {
- list = new ArrayList<>();
- levelToPackages.put(level, list);
- }
- list.add(packageName);
- }
- }
-
- final int size = levelToPackages.size();
- if (size == 0) {
+ SparseArray<List<String>> levelToPackages = getOwnersForDomainInternal(domain, false,
+ userId, pkgSettings);
+ if (levelToPackages.size() == 0) {
return emptyList();
}
- // Then sort them ascending by first installed time, with package name as tie breaker
- for (int index = 0; index < size; index++) {
- levelToPackages.valueAt(index).sort((first, second) -> {
- PackageSetting firstPkgSetting = pkgSettings.apply(first);
- PackageSetting secondPkgSetting = pkgSettings.apply(second);
-
- long firstInstallTime =
- firstPkgSetting == null ? -1L : firstPkgSetting.getFirstInstallTime();
- long secondInstallTime =
- secondPkgSetting == null ? -1L : secondPkgSetting.getFirstInstallTime();
-
- if (firstInstallTime != secondInstallTime) {
- return (int) (firstInstallTime - secondInstallTime);
- }
-
- return first.compareToIgnoreCase(second);
- });
- }
-
List<DomainOwner> owners = new ArrayList<>();
+ int size = levelToPackages.size();
for (int index = 0; index < size; index++) {
int level = levelToPackages.keyAt(index);
boolean overrideable = level <= APPROVAL_LEVEL_SELECTION;
@@ -811,6 +770,69 @@
});
}
+ /**
+ * @param includeNegative See {@link #approvalLevelForDomain(PackageSetting, String, boolean,
+ * int, Object)}.
+ * @return Mapping of approval level to packages; packages are sorted by firstInstallTime. Null
+ * if no owners were found.
+ */
+ @NonNull
+ private SparseArray<List<String>> getOwnersForDomainInternal(@NonNull String domain,
+ boolean includeNegative, @UserIdInt int userId,
+ @NonNull Function<String, PackageSetting> pkgSettingFunction) {
+ SparseArray<List<String>> levelToPackages = new SparseArray<>();
+ // First, collect the raw approval level values
+ synchronized (mLock) {
+ final int size = mAttachedPkgStates.size();
+ for (int index = 0; index < size; index++) {
+ DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
+ String packageName = pkgState.getPackageName();
+ PackageSetting pkgSetting = pkgSettingFunction.apply(packageName);
+ if (pkgSetting == null) {
+ continue;
+ }
+
+ int level = approvalLevelForDomain(pkgSetting, domain, includeNegative, userId,
+ domain);
+ if (!includeNegative && level <= APPROVAL_LEVEL_NONE) {
+ continue;
+ }
+ List<String> list = levelToPackages.get(level);
+ if (list == null) {
+ list = new ArrayList<>();
+ levelToPackages.put(level, list);
+ }
+ list.add(packageName);
+ }
+ }
+
+ final int size = levelToPackages.size();
+ if (size == 0) {
+ return levelToPackages;
+ }
+
+ // Then sort them ascending by first installed time, with package name as tie breaker
+ for (int index = 0; index < size; index++) {
+ levelToPackages.valueAt(index).sort((first, second) -> {
+ PackageSetting firstPkgSetting = pkgSettingFunction.apply(first);
+ PackageSetting secondPkgSetting = pkgSettingFunction.apply(second);
+
+ long firstInstallTime =
+ firstPkgSetting == null ? -1L : firstPkgSetting.getFirstInstallTime();
+ long secondInstallTime =
+ secondPkgSetting == null ? -1L : secondPkgSetting.getFirstInstallTime();
+
+ if (firstInstallTime != secondInstallTime) {
+ return (int) (firstInstallTime - secondInstallTime);
+ }
+
+ return first.compareToIgnoreCase(second);
+ });
+ }
+
+ return levelToPackages;
+ }
+
@NonNull
@Override
public UUID generateNewId() {
@@ -1153,6 +1175,88 @@
}
}
+ @Override
+ public void printOwnersForPackage(@NonNull IndentingPrintWriter writer,
+ @Nullable String packageName, @Nullable @UserIdInt Integer userId)
+ throws NameNotFoundException {
+ mConnection.withPackageSettingsThrowing(pkgSettings -> {
+ synchronized (mLock) {
+ if (packageName == null) {
+ int size = mAttachedPkgStates.size();
+ for (int index = 0; index < size; index++) {
+ try {
+ printOwnersForPackage(writer,
+ mAttachedPkgStates.valueAt(index).getPackageName(), userId,
+ pkgSettings);
+ } catch (NameNotFoundException ignored) {
+ // When iterating packages, if one doesn't exist somehow, ignore
+ }
+ }
+ } else {
+ printOwnersForPackage(writer, packageName, userId, pkgSettings);
+ }
+ }
+ });
+ }
+
+ private void printOwnersForPackage(@NonNull IndentingPrintWriter writer,
+ @NonNull String packageName, @Nullable @UserIdInt Integer userId,
+ @NonNull Function<String, PackageSetting> pkgSettingFunction)
+ throws NameNotFoundException {
+ PackageSetting pkgSetting = pkgSettingFunction.apply(packageName);
+ AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg();
+ if (pkg == null) {
+ throw DomainVerificationUtils.throwPackageUnavailable(packageName);
+ }
+
+ ArraySet<String> domains = mCollector.collectAllWebDomains(pkg);
+ int size = domains.size();
+ if (size == 0) {
+ return;
+ }
+
+ writer.println(packageName + ":");
+ writer.increaseIndent();
+
+ for (int index = 0; index < size; index++) {
+ printOwnersForDomain(writer, domains.valueAt(index), userId, pkgSettingFunction);
+ }
+
+ writer.decreaseIndent();
+ }
+
+ @Override
+ public void printOwnersForDomains(@NonNull IndentingPrintWriter writer,
+ @NonNull List<String> domains, @Nullable @UserIdInt Integer userId) {
+ mConnection.withPackageSettings(pkgSettings -> {
+ synchronized (mLock) {
+ int size = domains.size();
+ for (int index = 0; index < size; index++) {
+ printOwnersForDomain(writer, domains.get(index), userId, pkgSettings);
+ }
+ }
+ });
+ }
+
+ private void printOwnersForDomain(@NonNull IndentingPrintWriter writer, @NonNull String domain,
+ @Nullable @UserIdInt Integer userId,
+ @NonNull Function<String, PackageSetting> pkgSettingFunction) {
+ SparseArray<SparseArray<List<String>>> userIdToApprovalLevelToOwners =
+ new SparseArray<>();
+
+ if (userId == null || userId == UserHandle.USER_ALL) {
+ for (int aUserId : mConnection.getAllUserIds()) {
+ userIdToApprovalLevelToOwners.put(aUserId,
+ getOwnersForDomainInternal(domain, true, aUserId, pkgSettingFunction));
+ }
+ } else {
+ userIdToApprovalLevelToOwners.put(userId,
+ getOwnersForDomainInternal(domain, true, userId, pkgSettingFunction));
+ }
+
+ mDebug.printOwners(writer, domain, userIdToApprovalLevelToOwners);
+ }
+
@NonNull
@Override
public DomainVerificationShell getShell() {
@@ -1427,7 +1531,7 @@
// Find all approval levels
int highestApproval = fillMapWithApprovalLevels(infoApprovals, domain, userId,
pkgSettingFunction);
- if (highestApproval == APPROVAL_LEVEL_NONE) {
+ if (highestApproval <= APPROVAL_LEVEL_NONE) {
return Pair.create(emptyList(), highestApproval);
}
@@ -1484,7 +1588,7 @@
fillInfoMapForSamePackage(inputMap, packageName, APPROVAL_LEVEL_NONE);
continue;
}
- int approval = approvalLevelForDomain(pkgSetting, domain, userId, domain);
+ int approval = approvalLevelForDomain(pkgSetting, domain, false, userId, domain);
highestApproval = Math.max(highestApproval, approval);
fillInfoMapForSamePackage(inputMap, packageName, approval);
}
@@ -1600,18 +1704,53 @@
return APPROVAL_LEVEL_NONE;
}
- return approvalLevelForDomain(pkgSetting, intent.getData().getHost(), userId, intent);
+ return approvalLevelForDomain(pkgSetting, intent.getData().getHost(), false, userId,
+ intent);
}
/**
- * @param debugObject Should be an {@link Intent} if checking for resolution or a {@link String}
- * otherwise.
+ * @param includeNegative Whether to include negative values, which requires an expensive
+ * domain comparison operation.
+ * @param debugObject Should be an {@link Intent} if checking for resolution or a
+ * {@link String} otherwise.
*/
private int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull String host,
- @UserIdInt int userId, @NonNull Object debugObject) {
+ boolean includeNegative, @UserIdInt int userId, @NonNull Object debugObject) {
+ int approvalLevel = approvalLevelForDomainInternal(pkgSetting, host, includeNegative,
+ userId, debugObject);
+ if (includeNegative && approvalLevel == APPROVAL_LEVEL_NONE) {
+ PackageUserState pkgUserState = pkgSetting.readUserState(userId);
+ if (!pkgUserState.installed) {
+ return APPROVAL_LEVEL_NOT_INSTALLED;
+ }
+
+ AndroidPackage pkg = pkgSetting.getPkg();
+ if (pkg != null) {
+ if (!pkgUserState.isPackageEnabled(pkg)) {
+ return APPROVAL_LEVEL_DISABLED;
+ } else if (mCollector.containsAutoVerifyDomain(pkgSetting.getPkg(), host)) {
+ return APPROVAL_LEVEL_UNVERIFIED;
+ }
+ }
+ }
+
+ return approvalLevel;
+ }
+
+ private int approvalLevelForDomainInternal(@NonNull PackageSetting pkgSetting,
+ @NonNull String host, boolean includeNegative, @UserIdInt int userId,
+ @NonNull Object debugObject) {
String packageName = pkgSetting.getName();
final AndroidPackage pkg = pkgSetting.getPkg();
+ if (pkg != null && includeNegative && !mCollector.containsWebDomain(pkg, host)) {
+ if (DEBUG_APPROVAL) {
+ debugApproval(packageName, debugObject, userId, false,
+ "domain not declared");
+ }
+ return APPROVAL_LEVEL_UNDECLARED;
+ }
+
final PackageUserState pkgUserState = pkgSetting.readUserState(userId);
if (pkgUserState == null) {
if (DEBUG_APPROVAL) {
@@ -1749,6 +1888,7 @@
private Pair<List<String>, Integer> getApprovedPackagesLocked(@NonNull String domain,
@UserIdInt int userId, int minimumApproval,
@NonNull Function<String, PackageSetting> pkgSettingFunction) {
+ boolean includeNegative = minimumApproval < APPROVAL_LEVEL_NONE;
int highestApproval = minimumApproval;
List<String> approvedPackages = emptyList();
@@ -1762,7 +1902,8 @@
continue;
}
- int level = approvalLevelForDomain(pkgSetting, domain, userId, domain);
+ int level = approvalLevelForDomain(pkgSetting, domain, includeNegative, userId,
+ domain);
if (level < minimumApproval) {
continue;
}
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java
index ea71b28..da2d162 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java
@@ -110,6 +110,13 @@
pw.println(" packages will be reset if no one package is specified.");
pw.println(" <ALLOWED>: true to allow the package to open auto verified links, false");
pw.println(" to disable");
+ pw.println(" get-app-link-owners [--user <USER_ID>] [--package <PACKAGE>] [<DOMAINS>]");
+ pw.println(" Print the owners for a specific domain for a given user in low to high");
+ pw.println(" priority order.");
+ pw.println(" --user <USER_ID>: the user to query for");
+ pw.println(" --package <PACKAGE>: optionally also print for all web domains declared");
+ pw.println(" by a package, or \"all\" to print all packages");
+ pw.println(" --<DOMAINS>: space separated list of domains to query for");
}
/**
@@ -132,6 +139,8 @@
return runSetAppLinksUserState(commandHandler);
case "set-app-links-allowed":
return runSetAppLinksAllowed(commandHandler);
+ case "get-app-link-owners":
+ return runGetAppLinkOwners(commandHandler);
}
return null;
@@ -420,6 +429,67 @@
return true;
}
+ // pm get-app-link-owners [--user <USER_ID>] [--package <PACKAGE>] [<DOMAINS>]
+ private boolean runGetAppLinkOwners(@NonNull BasicShellCommandHandler commandHandler) {
+ String packageName = null;
+ Integer userId = null;
+ String option;
+ while ((option = commandHandler.getNextOption()) != null) {
+ switch (option) {
+ case "--user":
+ userId = UserHandle.parseUserArg(commandHandler.getNextArgRequired());
+ break;
+ case "--package":
+ packageName = commandHandler.getNextArgRequired();
+ if (TextUtils.isEmpty(packageName)) {
+ commandHandler.getErrPrintWriter().println("Error: no package specified");
+ return false;
+ }
+ break;
+ default:
+ commandHandler.getErrPrintWriter().println(
+ "Error: unexpected option: " + option);
+ return false;
+ }
+ }
+
+ ArrayList<String> domains = getRemainingArgs(commandHandler);
+ if (domains.isEmpty() && TextUtils.isEmpty(packageName)) {
+ commandHandler.getErrPrintWriter()
+ .println("Error: no package name or domain specified");
+ return false;
+ }
+
+ if (userId != null) {
+ userId = translateUserId(userId, "runSetAppLinksAllowed");
+ }
+
+ try (IndentingPrintWriter writer = new IndentingPrintWriter(
+ commandHandler.getOutPrintWriter(), /* singleIndent */ " ", /* wrapLength */
+ 120)) {
+ writer.increaseIndent();
+ if (packageName != null) {
+ if (packageName.equals("all")) {
+ packageName = null;
+ }
+
+ try {
+ mCallback.printOwnersForPackage(writer, packageName, userId);
+ } catch (NameNotFoundException e) {
+ commandHandler.getErrPrintWriter()
+ .println("Error: package not found: " + packageName);
+ return false;
+ }
+ }
+ if (!domains.isEmpty()) {
+ mCallback.printOwnersForDomains(writer, domains, userId);
+ }
+ writer.decreaseIndent();
+ return true;
+ }
+ }
+
+ @NonNull
private ArrayList<String> getRemainingArgs(@NonNull BasicShellCommandHandler commandHandler) {
ArrayList<String> args = new ArrayList<>();
String arg;
@@ -534,5 +604,18 @@
*/
void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName,
@Nullable @UserIdInt Integer userId) throws NameNotFoundException;
+
+ /**
+ * Print the owners for all domains in a given package.
+ */
+ void printOwnersForPackage(@NonNull IndentingPrintWriter writer,
+ @Nullable String packageName, @Nullable @UserIdInt Integer userId)
+ throws NameNotFoundException;
+
+ /**
+ * Print the owners for the given domains.
+ */
+ void printOwnersForDomains(@NonNull IndentingPrintWriter writer,
+ @NonNull List<String> domains, @Nullable @UserIdInt Integer userId);
}
}
diff --git a/services/core/java/com/android/server/testharness/TestHarnessModeService.java b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
index 52236a8..8b2b8b1 100644
--- a/services/core/java/com/android/server/testharness/TestHarnessModeService.java
+++ b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
@@ -284,6 +284,9 @@
private class TestHarnessModeShellCommand extends ShellCommand {
@Override
public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
switch (cmd) {
case "enable":
case "restore":
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 6ca3c4b..8f60b09c 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -52,7 +52,6 @@
import android.net.NetworkScore;
import android.net.RouteInfo;
import android.net.TelephonyNetworkSpecifier;
-import android.net.TunnelConnectionParams;
import android.net.Uri;
import android.net.annotations.PolicyDirection;
import android.net.ipsec.ike.ChildSessionCallback;
@@ -1924,14 +1923,8 @@
@NonNull IpSecTunnelInterface tunnelIface,
@NonNull VcnChildSessionConfiguration childConfig,
@Nullable UnderlyingNetworkRecord underlying) {
- final TunnelConnectionParams tunnelParams =
+ final IkeTunnelConnectionParams ikeTunnelParams =
gatewayConnectionConfig.getTunnelConnectionParams();
- if (!(tunnelParams instanceof IkeTunnelConnectionParams)) {
- throw new IllegalStateException(
- "TunnelConnectionParams is not IkeTunnelConnectionParams");
- }
-
- final IkeTunnelConnectionParams ikeTunnelParams = (IkeTunnelConnectionParams) tunnelParams;
final LinkProperties lp = new LinkProperties();
lp.setInterfaceName(tunnelIface.getInterfaceName());
@@ -2138,32 +2131,16 @@
}
private IkeSessionParams buildIkeParams(@NonNull Network network) {
- final TunnelConnectionParams tunnelConnectionParams =
+ final IkeTunnelConnectionParams ikeTunnelConnectionParams =
mConnectionConfig.getTunnelConnectionParams();
-
- if (tunnelConnectionParams instanceof IkeTunnelConnectionParams) {
- final IkeTunnelConnectionParams ikeTunnelConnectionParams =
- (IkeTunnelConnectionParams) tunnelConnectionParams;
- final IkeSessionParams.Builder builder =
- new IkeSessionParams.Builder(ikeTunnelConnectionParams.getIkeSessionParams());
- builder.setNetwork(network);
-
- return builder.build();
- }
-
- throw new IllegalStateException("TunnelConnectionParams is not IkeTunnelConnectionParams");
+ final IkeSessionParams.Builder builder =
+ new IkeSessionParams.Builder(ikeTunnelConnectionParams.getIkeSessionParams());
+ builder.setNetwork(network);
+ return builder.build();
}
private ChildSessionParams buildChildParams() {
- final TunnelConnectionParams tunnelConnectionParams =
- mConnectionConfig.getTunnelConnectionParams();
-
- if (tunnelConnectionParams instanceof IkeTunnelConnectionParams) {
- return ((IkeTunnelConnectionParams) tunnelConnectionParams)
- .getTunnelModeChildSessionParams();
- }
-
- throw new IllegalStateException("TunnelConnectionParams is not IkeTunnelConnectionParams");
+ return mConnectionConfig.getTunnelConnectionParams().getTunnelModeChildSessionParams();
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 9acbdcc..c888e54 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2384,17 +2384,19 @@
public void notifyWakingUp(int x, int y, @NonNull Bundle extras) {
synchronized (mLock) {
final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
- data.connection.forEachDisplayConnector(
- displayConnector -> {
- if (displayConnector.mEngine != null) {
- try {
- displayConnector.mEngine.dispatchWallpaperCommand(
- WallpaperManager.COMMAND_WAKING_UP, x, y, -1, extras);
- } catch (RemoteException e) {
- e.printStackTrace();
+ if (data != null && data.connection != null) {
+ data.connection.forEachDisplayConnector(
+ displayConnector -> {
+ if (displayConnector.mEngine != null) {
+ try {
+ displayConnector.mEngine.dispatchWallpaperCommand(
+ WallpaperManager.COMMAND_WAKING_UP, x, y, -1, extras);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
}
- }
- });
+ });
+ }
}
}
@@ -2404,17 +2406,20 @@
public void notifyGoingToSleep(int x, int y, @NonNull Bundle extras) {
synchronized (mLock) {
final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
- data.connection.forEachDisplayConnector(
- displayConnector -> {
- if (displayConnector.mEngine != null) {
- try {
- displayConnector.mEngine.dispatchWallpaperCommand(
- WallpaperManager.COMMAND_GOING_TO_SLEEP, x, y, -1, extras);
- } catch (RemoteException e) {
- e.printStackTrace();
+ if (data != null && data.connection != null) {
+ data.connection.forEachDisplayConnector(
+ displayConnector -> {
+ if (displayConnector.mEngine != null) {
+ try {
+ displayConnector.mEngine.dispatchWallpaperCommand(
+ WallpaperManager.COMMAND_GOING_TO_SLEEP, x, y, -1,
+ extras);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
}
- }
- });
+ });
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 98b1227..a97c080 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -48,6 +48,7 @@
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
+import android.graphics.BLASTBufferQueue;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
@@ -1123,7 +1124,8 @@
private final Paint mPaint = new Paint();
private final SurfaceControl mSurfaceControl;
- private final Surface mSurface = mService.mSurfaceFactory.get();
+ private final BLASTBufferQueue mBlastBufferQueue;
+ private final Surface mSurface;
private final AnimationController mAnimationController;
@@ -1135,11 +1137,10 @@
ViewportWindow(Context context) {
SurfaceControl surfaceControl = null;
try {
- mDisplay.getRealSize(mTempPoint);
surfaceControl = mDisplayContent
.makeOverlay()
.setName(SURFACE_TITLE)
- .setBufferSize(mTempPoint.x, mTempPoint.y) // not a typo
+ .setBLASTLayer()
.setFormat(PixelFormat.TRANSLUCENT)
.setCallsite("ViewportWindow")
.build();
@@ -1147,6 +1148,9 @@
/* ignore */
}
mSurfaceControl = surfaceControl;
+ mDisplay.getRealSize(mTempPoint);
+ mBlastBufferQueue = new BLASTBufferQueue(SURFACE_TITLE, mSurfaceControl,
+ mTempPoint.x, mTempPoint.y, PixelFormat.RGBA_8888);
final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
final int layer =
@@ -1156,8 +1160,7 @@
InputMonitor.setTrustedOverlayInputInfo(mSurfaceControl, t,
mDisplayContent.getDisplayId(), "Magnification Overlay");
t.apply();
-
- mSurface.copyFrom(mSurfaceControl);
+ mSurface = mBlastBufferQueue.createSurface();
mAnimationController = new AnimationController(context,
mService.mH.getLooper());
@@ -1282,6 +1285,9 @@
}
void releaseSurface() {
+ if (mBlastBufferQueue != null) {
+ mBlastBufferQueue.destroy();
+ }
mService.mTransactionFactory.get().remove(mSurfaceControl).apply();
mSurface.release();
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f279221..3e8bc5d 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3523,7 +3523,7 @@
}
// Reset the last saved PiP snap fraction on removal.
- mDisplayContent.mPinnedTaskControllerLocked.onActivityHidden(mActivityComponent);
+ mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent);
mWmService.mEmbeddedWindowController.onActivityRemoved(this);
mRemovingFromDisplay = false;
}
@@ -4882,7 +4882,7 @@
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this);
mAppStopped = true;
// Reset the last saved PiP snap fraction on app stop.
- mDisplayContent.mPinnedTaskControllerLocked.onActivityHidden(mActivityComponent);
+ mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent);
destroySurfaces();
// Remove any starting window that was added for this app if they are still around.
removeStartingWindow();
@@ -6405,8 +6405,8 @@
}
clearThumbnail();
final Transaction transaction = getAnimatingContainer().getPendingTransaction();
- mThumbnail = new WindowContainerThumbnail(mWmService.mSurfaceFactory,
- transaction, getAnimatingContainer(), thumbnailHeader);
+ mThumbnail = new WindowContainerThumbnail(transaction, getAnimatingContainer(),
+ thumbnailHeader);
mThumbnail.startAnimation(transaction, loadThumbnailAnimation(thumbnailHeader));
}
@@ -6435,8 +6435,7 @@
return;
}
final Transaction transaction = getPendingTransaction();
- mThumbnail = new WindowContainerThumbnail(mWmService.mSurfaceFactory,
- transaction, getTask(), thumbnail);
+ mThumbnail = new WindowContainerThumbnail(transaction, getTask(), thumbnail);
final Animation animation =
getDisplayContent().mAppTransition.createCrossProfileAppsThumbnailAnimationLocked(
frame);
@@ -6605,6 +6604,7 @@
return;
}
+ mDisplayContent.mPinnedTaskController.onCancelFixedRotationTransform(task);
// Perform rotation animation according to the rotation of this activity.
startFreezingScreen(originalDisplayRotation);
// This activity may relaunch or perform configuration change so once it has reported drawn,
@@ -6996,6 +6996,11 @@
// fixed-orientation requests.
return;
}
+ if (newParentConfig.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED) {
+ // PiP bounds have higher priority than the requested orientation. Otherwise the
+ // activity may be squeezed into a small piece.
+ return;
+ }
final Rect resolvedBounds =
getResolvedOverrideConfiguration().windowConfiguration.getBounds();
@@ -7387,8 +7392,9 @@
}
}
+ final boolean wasInPictureInPicture = inPinnedWindowingMode();
final DisplayContent display = mDisplayContent;
- if (inPinnedWindowingMode() && attachedToProcess() && display != null) {
+ if (wasInPictureInPicture && attachedToProcess() && display != null) {
// If the PIP activity is changing to fullscreen with display orientation change, the
// fixed rotation will take effect that requires to send fixed rotation adjustments
// before the process configuration (if the process is a configuration listener of the
@@ -7420,6 +7426,13 @@
onMergedOverrideConfigurationChanged();
}
+ // Before PiP animation is done, th windowing mode of the activity is still the previous
+ // mode (see RootWindowContainer#moveActivityToPinnedRootTask). So once the windowing mode
+ // of activity is changed, it is the signal of the last step to update the PiP states.
+ if (!wasInPictureInPicture && inPinnedWindowingMode() && task != null) {
+ mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, task.getBounds());
+ }
+
if (display == null) {
return;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 9be973b..08a9f09 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2761,8 +2761,8 @@
final boolean onTop =
(aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind;
- return mRootWindowContainer.getLaunchRootTask(r, aOptions, task, onTop, mLaunchParams,
- mRequest.realCallingPid, mRequest.realCallingUid);
+ return mRootWindowContainer.getLaunchRootTask(r, aOptions, task, mSourceRootTask, onTop,
+ mLaunchParams, launchFlags, mRequest.realCallingPid, mRequest.realCallingUid);
}
private boolean isLaunchModeOneOf(int mode1, int mode2) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 9d225e1..df1fec9 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2254,7 +2254,7 @@
scheduleUpdatePictureInPictureModeIfNeeded(task, rootTask.getRequestedOverrideBounds());
}
- private void scheduleUpdatePictureInPictureModeIfNeeded(Task task, Rect targetRootTaskBounds) {
+ void scheduleUpdatePictureInPictureModeIfNeeded(Task task, Rect targetRootTaskBounds) {
final PooledConsumer c = PooledLambda.obtainConsumer(
ActivityTaskSupervisor::addToPipModeChangedList, this,
PooledLambda.__(ActivityRecord.class));
@@ -2278,16 +2278,6 @@
mMultiWindowModeChangedActivities.remove(r);
}
- void updatePictureInPictureMode(Task task, Rect targetRootTaskBounds, boolean forceUpdate) {
- mHandler.removeMessages(REPORT_PIP_MODE_CHANGED_MSG);
- final PooledConsumer c = PooledLambda.obtainConsumer(
- ActivityRecord::updatePictureInPictureMode,
- PooledLambda.__(ActivityRecord.class), targetRootTaskBounds, forceUpdate);
- task.getRootTask().setBounds(targetRootTaskBounds);
- task.forAllActivities(c);
- c.recycle();
- }
-
void wakeUp(String reason) {
mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_APPLICATION,
"android.server.am:TURN_ON:" + reason);
diff --git a/services/core/java/com/android/server/wm/BlurController.java b/services/core/java/com/android/server/wm/BlurController.java
index d920267..ff10168 100644
--- a/services/core/java/com/android/server/wm/BlurController.java
+++ b/services/core/java/com/android/server/wm/BlurController.java
@@ -22,37 +22,32 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.os.PowerManager;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.provider.Settings;
import android.view.ICrossWindowBlurEnabledListener;
-import com.android.internal.annotations.GuardedBy;
-
/**
* Keeps track of the different factors that determine whether cross-window blur is enabled
* or disabled. Also keeps a list of all interested listeners and notifies them when the
* blur enabled state changes.
*/
final class BlurController {
- private final PowerManager mPowerManager;
+ private final Context mContext;
private final RemoteCallbackList<ICrossWindowBlurEnabledListener>
mBlurEnabledListeners = new RemoteCallbackList<>();
// We don't use the WM global lock, because the BlurController is not involved in window
// drawing and only receives binder calls that don't need synchronization with the rest of WM
private final Object mLock = new Object();
- @GuardedBy("mLock")
- boolean mBlurEnabled;
- @GuardedBy("mLock")
- boolean mBlurForceDisabled;
- @GuardedBy("mLock")
- boolean mInBatterySaverMode;
+ private volatile boolean mBlurEnabled;
+ private boolean mInPowerSaveMode;
+ private boolean mBlurDisabledSetting;
BlurController(Context context, PowerManager powerManager) {
- mPowerManager = powerManager;
- mInBatterySaverMode = mPowerManager.isPowerSaveMode();
- updateBlurEnabledLocked();
+ mContext = context;
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
@@ -60,18 +55,36 @@
@Override
public void onReceive(Context context, Intent intent) {
if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
- setBatterySaverEnabled(mPowerManager.isPowerSaveMode());
+ // onReceive always gets called on the same thread, so there is no
+ // multi-threaded execution here. Thus, we don't have to hold mLock here.
+ mInPowerSaveMode = powerManager.isPowerSaveMode();
+ updateBlurEnabled();
}
}
}, filter, null, null);
+ mInPowerSaveMode = powerManager.isPowerSaveMode();
+
+ context.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.DISABLE_WINDOW_BLURS), false,
+ new ContentObserver(null) {
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ // onChange always gets called on the same thread, so there is no
+ // multi-threaded execution here. Thus, we don't have to hold mLock here.
+ mBlurDisabledSetting = getBlurDisabledSetting();
+ updateBlurEnabled();
+ }
+ });
+ mBlurDisabledSetting = getBlurDisabledSetting();
+
+ updateBlurEnabled();
}
boolean registerCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) {
if (listener == null) return false;
mBlurEnabledListeners.register(listener);
- synchronized (mLock) {
- return mBlurEnabled;
- }
+ return getBlurEnabled();
}
void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) {
@@ -79,31 +92,22 @@
mBlurEnabledListeners.unregister(listener);
}
- void setForceCrossWindowBlurDisabled(boolean disable) {
- synchronized (mLock) {
- mBlurForceDisabled = disable;
- updateBlurEnabledLocked();
- }
-
+ boolean getBlurEnabled() {
+ return mBlurEnabled;
}
- void setBatterySaverEnabled(boolean enabled) {
+ private void updateBlurEnabled() {
synchronized (mLock) {
- mInBatterySaverMode = enabled;
- updateBlurEnabledLocked();
+ final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED && !mBlurDisabledSetting
+ && !mInPowerSaveMode;
+ if (mBlurEnabled == newEnabled) {
+ return;
+ }
+ mBlurEnabled = newEnabled;
+ notifyBlurEnabledChangedLocked(newEnabled);
}
}
- private void updateBlurEnabledLocked() {
- final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED && !mBlurForceDisabled
- && !mInBatterySaverMode;
- if (mBlurEnabled == newEnabled) {
- return;
- }
- mBlurEnabled = newEnabled;
- notifyBlurEnabledChangedLocked(newEnabled);
- }
-
private void notifyBlurEnabledChangedLocked(boolean enabled) {
int i = mBlurEnabledListeners.beginBroadcast();
while (i > 0) {
@@ -117,4 +121,9 @@
}
mBlurEnabledListeners.finishBroadcast();
}
+
+ private boolean getBlurDisabledSetting() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.DISABLE_WINDOW_BLURS, 0) == 1;
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c44f4e3..e28ab26 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -154,6 +154,8 @@
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
@@ -464,7 +466,7 @@
private boolean mDeferredRemoval;
final DockedTaskDividerController mDividerControllerLocked;
- final PinnedTaskController mPinnedTaskControllerLocked;
+ final PinnedTaskController mPinnedTaskController;
final ArrayList<WindowState> mTapExcludedWindows = new ArrayList<>();
/** A collection of windows that provide tap exclude regions inside of them. */
@@ -1017,7 +1019,7 @@
}
mWindowCornerRadius = mDisplayPolicy.getWindowCornerRadius();
mDividerControllerLocked = new DockedTaskDividerController(this);
- mPinnedTaskControllerLocked = new PinnedTaskController(mWmService, this);
+ mPinnedTaskController = new PinnedTaskController(mWmService, this);
final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(mSession)
.setOpaque(true)
@@ -1573,15 +1575,11 @@
}
return false;
}
- if (!r.getParent().matchParentBounds()) {
+ if (!r.getDisplayArea().matchParentBounds()) {
// Because the fixed rotated configuration applies to activity directly, if its parent
// has it own policy for bounds, the activity bounds based on parent is unknown.
return false;
}
- if (mPinnedTaskControllerLocked.isPipActiveOrWindowingModeChanging()) {
- // Use normal rotation animation because seamless PiP rotation is not supported yet.
- return false;
- }
setFixedRotationLaunchingApp(r, rotation);
return true;
@@ -1667,6 +1665,10 @@
if (mFixedRotationLaunchingApp == null) {
return;
}
+ if (mPinnedTaskController.shouldDeferOrientationChange()) {
+ // Wait for the PiP animation to finish.
+ return;
+ }
// Update directly because the app which will change the orientation of display is ready.
if (mDisplayRotation.updateOrientation(getOrientation(), false /* forceUpdate */)) {
sendNewConfiguration();
@@ -1837,6 +1839,7 @@
forAllWindows(w -> {
w.seamlesslyRotateIfAllowed(transaction, oldRotation, rotation, rotateSeamlessly);
}, true /* traverseTopToBottom */);
+ mPinnedTaskController.startSeamlessRotationIfNeeded(transaction);
}
mWmService.mDisplayManagerInternal.performTraversal(transaction);
@@ -2333,7 +2336,7 @@
}
PinnedTaskController getPinnedTaskController() {
- return mPinnedTaskControllerLocked;
+ return mPinnedTaskController;
}
/**
@@ -2392,12 +2395,11 @@
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
- // update resources before cascade so that root docked/pinned tasks use the correct info
- preOnConfigurationChanged();
final int lastOrientation = getConfiguration().orientation;
super.onConfigurationChanged(newParentConfig);
if (mDisplayPolicy != null) {
mDisplayPolicy.onConfigurationChanged();
+ mPinnedTaskController.onPostDisplayConfigurationChanged();
}
if (lastOrientation != getConfiguration().orientation) {
@@ -2408,19 +2410,6 @@
}
}
- /**
- * Updates the resources used by docked/pinned controllers. This needs to be called at the
- * beginning of a configuration update cascade since the metrics from these resources are used
- * for bounds calculations.
- */
- void preOnConfigurationChanged() {
- final PinnedTaskController pinnedTaskController = getPinnedTaskController();
-
- if (pinnedTaskController != null) {
- getPinnedTaskController().onConfigurationChanged();
- }
- }
-
@Override
boolean fillsParent() {
return true;
@@ -2962,7 +2951,7 @@
final boolean imeVisible = imeWin != null && imeWin.isVisible()
&& imeWin.isDisplayed();
final int imeHeight = getInputMethodWindowVisibleHeight();
- mPinnedTaskControllerLocked.setAdjustedForIme(imeVisible, imeHeight);
+ mPinnedTaskController.setAdjustedForIme(imeVisible, imeHeight);
}
int getInputMethodWindowVisibleHeight() {
@@ -3190,7 +3179,7 @@
}
pw.println();
- mPinnedTaskControllerLocked.dump(prefix, pw);
+ mPinnedTaskController.dump(prefix, pw);
pw.println();
mDisplayFrames.dump(prefix, pw);
@@ -3821,7 +3810,7 @@
final ActivityRecord activity = mImeLayeringTarget.mActivityRecord;
final SurfaceControl imeSurface = mWmService.mSurfaceControlFactory.apply(null)
.setName("IME-snapshot-surface")
- .setBufferSize(buffer.getWidth(), buffer.getHeight())
+ .setBLASTLayer()
.setFormat(buffer.getFormat())
.setParent(activity.getSurfaceControl())
.setCallsite("DisplayContent.attachAndShowImeScreenshotOnTarget")
@@ -3829,10 +3818,9 @@
// Make IME snapshot as trusted overlay
InputMonitor.setTrustedOverlayInputInfo(imeSurface, t, getDisplayId(),
"IME-snapshot-surface");
- Surface surface = mWmService.mSurfaceFactory.get();
- surface.copyFrom(imeSurface);
- surface.attachAndQueueBufferWithColorSpace(buffer, null);
- surface.release();
+ GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(buffer);
+ t.setBuffer(imeSurface, graphicBuffer);
+ t.setColorSpace(mSurfaceControl, ColorSpace.get(ColorSpace.Named.SRGB));
t.setRelativeLayer(imeSurface, activity.getSurfaceControl(), 1);
t.setPosition(imeSurface, mInputMethodWindow.getDisplayFrame().left,
mInputMethodWindow.getDisplayFrame().top);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index e1fc75e..0e73d79 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -254,7 +254,7 @@
if (isDefaultDisplay) {
final Handler uiHandler = UiThread.getHandler();
- mOrientationListener = new OrientationListener(mContext, uiHandler, mService);
+ mOrientationListener = new OrientationListener(mContext, uiHandler);
mOrientationListener.setCurrentRotation(mRotation);
mSettingsObserver = new SettingsObserver(uiHandler);
mSettingsObserver.observe();
@@ -1514,8 +1514,8 @@
final SparseArray<Runnable> mRunnableCache = new SparseArray<>(5);
boolean mEnabled;
- OrientationListener(Context context, Handler handler, WindowManagerService service) {
- super(context, handler, service);
+ OrientationListener(Context context, Handler handler) {
+ super(context, handler);
}
private class UpdateRunnable implements Runnable {
diff --git a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
index 724747d..02a7db1 100644
--- a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
+++ b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
@@ -20,38 +20,39 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.content.Context;
+import android.graphics.BLASTBufferQueue;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PorterDuff;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.Display;
import android.view.Surface;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
-import java.util.function.Supplier;
-
class EmulatorDisplayOverlay {
private static final String TAG = TAG_WITH_CLASS_NAME ? "EmulatorDisplayOverlay" : TAG_WM;
+ private static final String TITLE = "EmulatorDisplayOverlay";
+
// Display dimensions
private Point mScreenSize;
private final SurfaceControl mSurfaceControl;
private final Surface mSurface;
+ private final BLASTBufferQueue mBlastBufferQueue;
+
private int mLastDW;
private int mLastDH;
private boolean mDrawNeeded;
- private Drawable mOverlay;
+ private final Drawable mOverlay;
private int mRotation;
private boolean mVisible;
- EmulatorDisplayOverlay(Supplier<Surface> surfaceFactory, Context context, DisplayContent dc,
- int zOrder, SurfaceControl.Transaction t) {
- mSurface = surfaceFactory.get();
+ EmulatorDisplayOverlay(Context context, DisplayContent dc, int zOrder,
+ SurfaceControl.Transaction t) {
final Display display = dc.getDisplay();
mScreenSize = new Point();
display.getSize(mScreenSize);
@@ -59,24 +60,26 @@
SurfaceControl ctrl = null;
try {
ctrl = dc.makeOverlay()
- .setName("EmulatorDisplayOverlay")
- .setBufferSize(mScreenSize.x, mScreenSize.y)
+ .setName(TITLE)
+ .setBLASTLayer()
.setFormat(PixelFormat.TRANSLUCENT)
- .setCallsite("EmulatorDisplayOverlay")
+ .setCallsite(TITLE)
.build();
t.setLayer(ctrl, zOrder);
t.setPosition(ctrl, 0, 0);
t.show(ctrl);
// Ensure we aren't considered as obscuring for Input purposes.
- InputMonitor.setTrustedOverlayInputInfo(ctrl, t,
- dc.getDisplayId(), "EmulatorDisplayOverlay");
- mSurface.copyFrom(ctrl);
+ InputMonitor.setTrustedOverlayInputInfo(ctrl, t, dc.getDisplayId(), TITLE);
} catch (OutOfResourcesException e) {
}
mSurfaceControl = ctrl;
mDrawNeeded = true;
mOverlay = context.getDrawable(
com.android.internal.R.drawable.emulator_circular_window_overlay);
+
+ mBlastBufferQueue = new BLASTBufferQueue(TITLE, mSurfaceControl, mScreenSize.x,
+ mScreenSize.y, PixelFormat.RGBA_8888);
+ mSurface = mBlastBufferQueue.createSurface();
}
private void drawIfNeeded(SurfaceControl.Transaction t) {
@@ -85,12 +88,10 @@
}
mDrawNeeded = false;
- Rect dirty = new Rect(0, 0, mScreenSize.x, mScreenSize.y);
Canvas c = null;
try {
- c = mSurface.lockCanvas(dirty);
- } catch (IllegalArgumentException e) {
- } catch (OutOfResourcesException e) {
+ c = mSurface.lockCanvas(null);
+ } catch (IllegalArgumentException | OutOfResourcesException e) {
}
if (c == null) {
return;
diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
index 15e078b..dea83f0 100644
--- a/services/core/java/com/android/server/wm/PinnedTaskController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -16,20 +16,26 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.app.PictureInPictureParams;
import android.app.RemoteAction;
import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
+import android.graphics.Matrix;
+import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
-import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Slog;
-import android.view.DisplayInfo;
import android.view.IPinnedTaskListener;
+import android.view.SurfaceControl;
+import android.window.PictureInPictureSurfaceTransaction;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -54,6 +60,7 @@
class PinnedTaskController {
private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedTaskController" : TAG_WM;
+ private static final int DEFER_ORIENTATION_CHANGE_TIMEOUT_MS = 1000;
private final WindowManagerService mService;
private final DisplayContent mDisplayContent;
@@ -62,8 +69,21 @@
private final PinnedTaskListenerDeathHandler mPinnedTaskListenerDeathHandler =
new PinnedTaskListenerDeathHandler();
- /** Whether the PiP is entering or leaving. */
- private boolean mIsPipWindowingModeChanging;
+ /**
+ * Non-null if the entering PiP task will cause display rotation to change. The bounds are
+ * based on the new rotation.
+ */
+ private Rect mDestRotatedBounds;
+ /**
+ * Non-null if the entering PiP task from recents animation will cause display rotation to
+ * change. The transaction is based on the old rotation.
+ */
+ private PictureInPictureSurfaceTransaction mPipTransaction;
+ /** Whether to skip task configuration change once. */
+ private boolean mFreezingTaskConfig;
+ /** Defer display orientation change if the PiP task is animating across orientations. */
+ private boolean mDeferOrientationChanging;
+ private final Runnable mDeferOrientationTimeoutRunnable;
private boolean mIsImeShowing;
private int mImeHeight;
@@ -72,16 +92,10 @@
private ArrayList<RemoteAction> mActions = new ArrayList<>();
private float mAspectRatio = -1f;
- // Used to calculate task bounds across rotations
- private final DisplayInfo mDisplayInfo = new DisplayInfo();
-
// The aspect ratio bounds of the PIP.
private float mMinAspectRatio;
private float mMaxAspectRatio;
- // Temp vars for calculation
- private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
-
/**
* Handler for the case where the listener dies.
*/
@@ -89,23 +103,32 @@
@Override
public void binderDied() {
- // Clean up the state if the listener dies
- if (mPinnedTaskListener != null) {
- mPinnedTaskListener.asBinder().unlinkToDeath(mPinnedTaskListenerDeathHandler, 0);
+ synchronized (mService.mGlobalLock) {
+ mPinnedTaskListener = null;
+ mFreezingTaskConfig = false;
+ mDeferOrientationTimeoutRunnable.run();
}
- mPinnedTaskListener = null;
}
}
PinnedTaskController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
mDisplayContent = displayContent;
- mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
+ mDeferOrientationTimeoutRunnable = () -> {
+ synchronized (mService.mGlobalLock) {
+ if (mDeferOrientationChanging) {
+ continueOrientationChange();
+ mService.mWindowPlacerLocked.requestTraversal();
+ }
+ }
+ };
reloadResources();
}
- void onConfigurationChanged() {
+ /** Updates the resources used by pinned controllers. */
+ void onPostDisplayConfigurationChanged() {
reloadResources();
+ mFreezingTaskConfig = false;
}
/**
@@ -113,7 +136,6 @@
*/
private void reloadResources() {
final Resources res = mService.mContext.getResources();
- mDisplayContent.getDisplay().getRealMetrics(mTmpMetrics);
mMinAspectRatio = res.getFloat(
com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
mMaxAspectRatio = res.getFloat(
@@ -143,18 +165,150 @@
&& Float.compare(aspectRatio, mMaxAspectRatio) <= 0;
}
- /** Returns {@code true} if the PiP is on screen or is changing windowing mode. */
- boolean isPipActiveOrWindowingModeChanging() {
- if (mIsPipWindowingModeChanging) {
- return true;
+ /**
+ * Called when a fullscreen task is entering PiP with display orientation change. This is used
+ * to avoid flickering when running PiP animation across different orientations.
+ */
+ void deferOrientationChangeForEnteringPipFromFullScreenIfNeeded() {
+ final Task topFullscreenTask = mDisplayContent.getDefaultTaskDisplayArea()
+ .getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ final ActivityRecord topFullscreen = topFullscreenTask != null
+ ? topFullscreenTask.topRunningActivity() : null;
+ if (topFullscreen == null || topFullscreen.hasFixedRotationTransform()) {
+ return;
}
- final Task pinnedTask = mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask();
- return pinnedTask != null && pinnedTask.hasChild();
+ final int rotation = mDisplayContent.rotationForActivityInDifferentOrientation(
+ topFullscreen);
+ if (rotation == ROTATION_UNDEFINED) {
+ return;
+ }
+ // If the next top activity will change the orientation of display, start fixed rotation to
+ // notify PipTaskOrganizer before it receives task appeared. And defer display orientation
+ // update until the new PiP bounds are set.
+ mDisplayContent.setFixedRotationLaunchingApp(topFullscreen, rotation);
+ mDeferOrientationChanging = true;
+ mService.mH.removeCallbacks(mDeferOrientationTimeoutRunnable);
+ final float animatorScale = Math.max(1, mService.getCurrentAnimatorScale());
+ mService.mH.postDelayed(mDeferOrientationTimeoutRunnable,
+ (int) (animatorScale * DEFER_ORIENTATION_CHANGE_TIMEOUT_MS));
}
- /** Sets whether a visible task is changing from or to pinned mode. */
- void setPipWindowingModeChanging(boolean isPipWindowingModeChanging) {
- mIsPipWindowingModeChanging = isPipWindowingModeChanging;
+ /** Defers orientation change while there is a top fixed rotation activity. */
+ boolean shouldDeferOrientationChange() {
+ return mDeferOrientationChanging;
+ }
+
+ /**
+ * Sets the bounds for {@link #startSeamlessRotationIfNeeded} if the orientation of display
+ * will be changed.
+ */
+ void setEnterPipBounds(Rect bounds) {
+ if (!mDeferOrientationChanging) {
+ return;
+ }
+ mFreezingTaskConfig = true;
+ mDestRotatedBounds = new Rect(bounds);
+ continueOrientationChange();
+ }
+
+ /**
+ * Sets the transaction for {@link #startSeamlessRotationIfNeeded} if the orientation of display
+ * will be changed. This is only called when finishing recents animation with pending
+ * orientation change that will be handled by
+ * {@link DisplayContent.FixedRotationTransitionListener#onFinishRecentsAnimation}.
+ */
+ void setEnterPipTransaction(PictureInPictureSurfaceTransaction tx) {
+ mFreezingTaskConfig = true;
+ mPipTransaction = tx;
+ }
+
+ /** Called when the activity in PiP task has PiP windowing mode (at the end of animation). */
+ private void continueOrientationChange() {
+ mDeferOrientationChanging = false;
+ mService.mH.removeCallbacks(mDeferOrientationTimeoutRunnable);
+ final WindowContainer<?> orientationSource = mDisplayContent.getLastOrientationSource();
+ if (orientationSource != null && !orientationSource.isAppTransitioning()) {
+ mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
+ }
+ }
+
+ /**
+ * Resets rotation and applies scale and position to PiP task surface to match the current
+ * rotation of display. The final surface matrix will be replaced by PiPTaskOrganizer after it
+ * receives the callback of fixed rotation completion.
+ */
+ void startSeamlessRotationIfNeeded(SurfaceControl.Transaction t) {
+ final Rect bounds = mDestRotatedBounds;
+ final PictureInPictureSurfaceTransaction pipTx = mPipTransaction;
+ if (bounds == null && pipTx == null) {
+ return;
+ }
+ final TaskDisplayArea taskArea = mDisplayContent.getDefaultTaskDisplayArea();
+ final Task pinnedTask = taskArea.getRootPinnedTask();
+ if (pinnedTask == null) {
+ return;
+ }
+
+ mDestRotatedBounds = null;
+ mPipTransaction = null;
+ final Rect areaBounds = taskArea.getBounds();
+ if (pipTx != null) {
+ // The transaction from recents animation is in old rotation. So the position needs to
+ // be rotated.
+ float dx = pipTx.mPositionX;
+ float dy = pipTx.mPositionY;
+ if (pipTx.mRotation == 90) {
+ dx = pipTx.mPositionY;
+ dy = areaBounds.right - pipTx.mPositionX;
+ } else if (pipTx.mRotation == -90) {
+ dx = areaBounds.bottom - pipTx.mPositionY;
+ dy = pipTx.mPositionX;
+ }
+ final Matrix matrix = new Matrix();
+ matrix.setScale(pipTx.mScaleX, pipTx.mScaleY);
+ matrix.postTranslate(dx, dy);
+ t.setMatrix(pinnedTask.getSurfaceControl(), matrix, new float[9]);
+ Slog.i(TAG, "Seamless rotation PiP tx=" + pipTx + " pos=" + dx + "," + dy);
+ return;
+ }
+
+ final PictureInPictureParams params = pinnedTask.getPictureInPictureParams();
+ final Rect sourceHintRect = params != null && params.hasSourceBoundsHint()
+ ? params.getSourceRectHint()
+ : null;
+ Slog.i(TAG, "Seamless rotation PiP bounds=" + bounds + " hintRect=" + sourceHintRect);
+ final Rect contentBounds = sourceHintRect != null && areaBounds.contains(sourceHintRect)
+ ? sourceHintRect : areaBounds;
+ final int w = contentBounds.width();
+ final int h = contentBounds.height();
+ final float scale = w <= h ? (float) bounds.width() / w : (float) bounds.height() / h;
+ final int insetLeft = (int) ((contentBounds.left - areaBounds.left) * scale + .5f);
+ final int insetTop = (int) ((contentBounds.top - areaBounds.top) * scale + .5f);
+ final Matrix matrix = new Matrix();
+ matrix.setScale(scale, scale);
+ matrix.postTranslate(bounds.left - insetLeft, bounds.top - insetTop);
+ t.setMatrix(pinnedTask.getSurfaceControl(), matrix, new float[9]);
+ }
+
+ /**
+ * Returns {@code true} to skip {@link Task#onConfigurationChanged} because it is expected that
+ * there will be a orientation change and a PiP configuration change.
+ */
+ boolean isFreezingTaskConfig(Task task) {
+ return mFreezingTaskConfig
+ && task == mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask();
+ }
+
+ /** Resets the states which were used to perform fixed rotation with PiP task. */
+ void onCancelFixedRotationTransform(Task task) {
+ mFreezingTaskConfig = false;
+ mDeferOrientationChanging = false;
+ mDestRotatedBounds = null;
+ mPipTransaction = null;
+ if (!task.isOrganized()) {
+ // Force clearing Task#mForceNotOrganized because the display didn't rotate.
+ task.onConfigurationChanged(task.getParent().getConfiguration());
+ }
}
/**
@@ -272,6 +426,14 @@
void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "PinnedTaskController");
+ if (mDeferOrientationChanging) pw.println(prefix + " mDeferOrientationChanging=true");
+ if (mFreezingTaskConfig) pw.println(prefix + " mFreezingTaskConfig=true");
+ if (mDestRotatedBounds != null) {
+ pw.println(prefix + " mPendingBounds=" + mDestRotatedBounds);
+ }
+ if (mPipTransaction != null) {
+ pw.println(prefix + " mPipTransaction=" + mPipTransaction);
+ }
pw.println(prefix + " mIsImeShowing=" + mIsImeShowing);
pw.println(prefix + " mImeHeight=" + mImeHeight);
pw.println(prefix + " mAspectRatio=" + mAspectRatio);
@@ -288,6 +450,5 @@
}
pw.println(prefix + " ]");
}
- pw.println(prefix + " mDisplayInfo=" + mDisplayInfo);
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index e165dfa..dec6460 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -1146,6 +1146,11 @@
PictureInPictureSurfaceTransaction.apply(mFinishTransaction,
mTask.mSurfaceControl, pendingTransaction);
mTask.setLastRecentsAnimationTransaction(mFinishTransaction);
+ if (mDisplayContent.isFixedRotationLaunchingApp(mTargetActivityRecord)) {
+ // The transaction is needed for position when rotating the display.
+ mDisplayContent.mPinnedTaskController.setEnterPipTransaction(
+ mFinishTransaction);
+ }
mFinishTransaction = null;
pendingTransaction.apply();
} else if (!mTask.isAttached()) {
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 67bc7af..1a429f8 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -55,7 +55,7 @@
class RemoteAnimationController implements DeathRecipient {
private static final String TAG = TAG_WITH_CLASS_NAME
? "RemoteAnimationController" : TAG_WM;
- private static final long TIMEOUT_MS = 2000;
+ private static final long TIMEOUT_MS = 10000;
private final WindowManagerService mService;
private final DisplayContent mDisplayContent;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index c81f31e..d9c5fa4 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2810,10 +2810,11 @@
return false;
}
- Task getLaunchRootTask(@Nullable ActivityRecord r,
- @Nullable ActivityOptions options, @Nullable Task candidateTask, boolean onTop) {
- return getLaunchRootTask(r, options, candidateTask, onTop, null /* launchParams */,
- -1 /* no realCallingPid */, -1 /* no realCallingUid */);
+ Task getLaunchRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+ @Nullable Task candidateTask, boolean onTop) {
+ return getLaunchRootTask(r, options, candidateTask, null /* sourceTask */, onTop,
+ null /* launchParams */, 0 /* launchFlags */, -1 /* no realCallingPid */,
+ -1 /* no realCallingUid */);
}
/**
@@ -2822,15 +2823,18 @@
* @param r The activity we are trying to launch. Can be null.
* @param options The activity options used to the launch. Can be null.
* @param candidateTask The possible task the activity might be launched in. Can be null.
+ * @param sourceTask The task requesting to start activity. Can be null.
* @param launchParams The resolved launch params to use.
+ * @param launchFlags The launch flags for this launch.
* @param realCallingPid The pid from {@link ActivityStarter#setRealCallingPid}
* @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid}
* @return The root task to use for the launch or INVALID_TASK_ID.
*/
Task getLaunchRootTask(@Nullable ActivityRecord r,
- @Nullable ActivityOptions options, @Nullable Task candidateTask, boolean onTop,
- @Nullable LaunchParamsController.LaunchParams launchParams, int realCallingPid,
- int realCallingUid) {
+ @Nullable ActivityOptions options, @Nullable Task candidateTask,
+ @Nullable Task sourceTask, boolean onTop,
+ @Nullable LaunchParamsController.LaunchParams launchParams, int launchFlags,
+ int realCallingPid, int realCallingUid) {
int taskId = INVALID_TASK_ID;
int displayId = INVALID_DISPLAY;
TaskDisplayArea taskDisplayArea = null;
@@ -2894,7 +2898,7 @@
// Falling back to default task container
taskDisplayArea = taskDisplayArea.mDisplayContent.getDefaultTaskDisplayArea();
rootTask = taskDisplayArea.getOrCreateRootTask(r, options, candidateTask,
- launchParams, activityType, onTop);
+ sourceTask, launchParams, launchFlags, activityType, onTop);
if (rootTask != null) {
return rootTask;
}
@@ -2949,8 +2953,8 @@
}
}
- return container.getOrCreateRootTask(
- r, options, candidateTask, launchParams, activityType, onTop);
+ return container.getOrCreateRootTask(r, options, candidateTask, sourceTask, launchParams,
+ launchFlags, activityType, onTop);
}
/** @return true if activity record is null or can be launched on provided display. */
diff --git a/services/core/java/com/android/server/wm/StrictModeFlash.java b/services/core/java/com/android/server/wm/StrictModeFlash.java
index 39ac16a..48a7bde 100644
--- a/services/core/java/com/android/server/wm/StrictModeFlash.java
+++ b/services/core/java/com/android/server/wm/StrictModeFlash.java
@@ -19,6 +19,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.graphics.BLASTBufferQueue;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
@@ -27,28 +28,27 @@
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
-import java.util.function.Supplier;
-
class StrictModeFlash {
private static final String TAG = TAG_WITH_CLASS_NAME ? "StrictModeFlash" : TAG_WM;
+ private static final String TITLE = "StrictModeFlash";
private final SurfaceControl mSurfaceControl;
private final Surface mSurface;
+ private final BLASTBufferQueue mBlastBufferQueue;
+
private int mLastDW;
private int mLastDH;
private boolean mDrawNeeded;
private final int mThickness = 20;
- StrictModeFlash(Supplier<Surface> surfaceFactory, DisplayContent dc,
- SurfaceControl.Transaction t) {
- mSurface = surfaceFactory.get();
+ StrictModeFlash(DisplayContent dc, SurfaceControl.Transaction t) {
SurfaceControl ctrl = null;
try {
ctrl = dc.makeOverlay()
- .setName("StrictModeFlash")
- .setBufferSize(1, 1)
+ .setName(TITLE)
+ .setBLASTLayer()
.setFormat(PixelFormat.TRANSLUCENT)
- .setCallsite("StrictModeFlash")
+ .setCallsite(TITLE)
.build();
// one more than Watermark? arbitrary.
@@ -56,14 +56,15 @@
t.setPosition(ctrl, 0, 0);
t.show(ctrl);
// Ensure we aren't considered as obscuring for Input purposes.
- InputMonitor.setTrustedOverlayInputInfo(ctrl, t, dc.getDisplayId(),
- "StrictModeFlash");
-
- mSurface.copyFrom(ctrl);
+ InputMonitor.setTrustedOverlayInputInfo(ctrl, t, dc.getDisplayId(), TITLE);
} catch (OutOfResourcesException e) {
}
mSurfaceControl = ctrl;
mDrawNeeded = true;
+
+ mBlastBufferQueue = new BLASTBufferQueue(TITLE, mSurfaceControl, 1 /* width */,
+ 1 /* height */, PixelFormat.RGBA_8888);
+ mSurface = mBlastBufferQueue.createSurface();
}
private void drawIfNeeded() {
@@ -73,13 +74,12 @@
mDrawNeeded = false;
final int dw = mLastDW;
final int dh = mLastDH;
+ mBlastBufferQueue.update(mSurfaceControl, dw, dh, PixelFormat.RGBA_8888);
- Rect dirty = new Rect(0, 0, dw, dh);
Canvas c = null;
try {
- c = mSurface.lockCanvas(dirty);
- } catch (IllegalArgumentException e) {
- } catch (Surface.OutOfResourcesException e) {
+ c = mSurface.lockCanvas(null);
+ } catch (IllegalArgumentException | OutOfResourcesException e) {
}
if (c == null) {
return;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d56d73a..2a0041a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -176,12 +176,14 @@
import android.app.servertransaction.PauseActivityItem;
import android.app.servertransaction.ResumeActivityItem;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
@@ -2267,7 +2269,6 @@
}
if (pipChanging) {
- mDisplayContent.getPinnedTaskController().setPipWindowingModeChanging(true);
// If the top activity is using fixed rotation, it should be changing from PiP to
// fullscreen with display orientation change. Do not notify fullscreen task organizer
// because the restoration of task surface and the transformation of activity surface
@@ -2276,29 +2277,15 @@
if (r != null && mDisplayContent.isFixedRotationLaunchingApp(r)) {
mForceNotOrganized = true;
}
- } else if (mForceNotOrganized) {
+ } else {
// If the display orientation change is done, let the corresponding task organizer take
// back the control of this task.
- final ActivityRecord r = topRunningActivity();
- if (r == null || !mDisplayContent.isFixedRotationLaunchingApp(r)) {
- mForceNotOrganized = false;
- }
+ mForceNotOrganized = false;
}
- try {
- // We have 2 reasons why we need to report orientation change here.
- // 1. In some cases (e.g. freeform -> fullscreen) we don't have other ways of reporting.
- // 2. Report orientation as soon as possible so that the display can freeze earlier if
- // the display orientation will be changed. Because the surface bounds of activity
- // may have been set to fullscreen but the activity hasn't redrawn its content yet,
- // the rotation animation needs to capture snapshot earlier to avoid animating from
- // an intermediate state.
- if (oldOrientation != getOrientation()) {
- onDescendantOrientationChanged(this);
- }
- } finally {
- if (pipChanging) {
- mDisplayContent.getPinnedTaskController().setPipWindowingModeChanging(false);
- }
+
+ // Report orientation change such as changing from freeform to fullscreen.
+ if (oldOrientation != getOrientation()) {
+ onDescendantOrientationChanged(this);
}
saveLaunchingStateIfNeeded();
@@ -2321,6 +2308,15 @@
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
+ if (mDisplayContent != null
+ && mDisplayContent.mPinnedTaskController.isFreezingTaskConfig(this)) {
+ // It happens when animating from fullscreen to PiP with orientation change. Because
+ // the activity in this pinned task is in fullscreen windowing mode (see
+ // RootWindowContainer#moveActivityToPinnedRootTask) and the activity will be set to
+ // pinned mode after the animation is done, the configuration change by orientation
+ // change is just an intermediate state that should be ignored to avoid flickering.
+ return;
+ }
// Calling Task#onConfigurationChanged() for leaf task since the ops in this method are
// particularly for root tasks, like preventing bounds changes when inheriting certain
// windowing mode.
@@ -4471,10 +4467,10 @@
pw.print(" mSupportsPictureInPicture="); pw.print(mSupportsPictureInPicture);
pw.print(" isResizeable="); pw.println(isResizeable());
pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime);
+ pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
if (mForceNotOrganized) {
pw.print(prefix); pw.println("mForceNotOrganized=true");
}
- pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
}
@Override
@@ -5437,6 +5433,13 @@
// Nothing else to do if we don't have a window container yet. E.g. call from ctor.
return;
}
+
+ // From fullscreen to PiP.
+ if (topActivity != null && currentMode == WINDOWING_MODE_FULLSCREEN
+ && windowingMode == WINDOWING_MODE_PINNED) {
+ mDisplayContent.mPinnedTaskController
+ .deferOrientationChangeForEnteringPipFromFullScreenIfNeeded();
+ }
} finally {
mAtmService.continueWindowLayout();
}
@@ -6676,8 +6679,30 @@
prev = null;
}
}
- final int splashScreenThemeResId = options != null
+
+ // TODO(185200798): Persist theme name instead of theme if
+ int splashScreenThemeResId = options != null
? options.getSplashScreenThemeResId() : 0;
+
+ // User can override the splashscreen theme. The theme name is used to persist
+ // the setting, so if no theme is set in the ActivityOptions, we check if has
+ // been persisted here.
+ if (splashScreenThemeResId == 0) {
+ try {
+ String themeName = mAtmService.getPackageManager()
+ .getSplashScreenTheme(r.packageName, r.mUserId);
+ if (themeName != null) {
+ Context packageContext = mAtmService.mContext
+ .createPackageContext(r.packageName, 0);
+ splashScreenThemeResId = packageContext.getResources()
+ .getIdentifier(themeName, null, null);
+ }
+ } catch (RemoteException | PackageManager.NameNotFoundException
+ | Resources.NotFoundException ignore) {
+ // Just use the default theme
+ }
+ }
+
r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity),
splashScreenThemeResId, samePackage);
}
@@ -7927,6 +7952,17 @@
private boolean mHasBeenVisible;
private boolean mRemoveWithTaskOrganizer;
+ /**
+ * Records the source task that requesting to build a new task, used to determine which of
+ * the adjacent roots should be launch root of the new task.
+ */
+ private Task mSourceTask;
+
+ /**
+ * Records launch flags to apply when launching new task.
+ */
+ private int mLaunchFlags;
+
Builder(ActivityTaskManagerService atm) {
mAtmService = atm;
}
@@ -7936,6 +7972,16 @@
return this;
}
+ Builder setSourceTask(Task sourceTask) {
+ mSourceTask = sourceTask;
+ return this;
+ }
+
+ Builder setLaunchFlags(int launchFlags) {
+ mLaunchFlags = launchFlags;
+ return this;
+ }
+
Builder setTaskId(int taskId) {
mTaskId = taskId;
return this;
@@ -8190,9 +8236,14 @@
tda.getRootPinnedTask().dismissPip();
}
+ if (mIntent != null) {
+ mLaunchFlags |= mIntent.getFlags();
+ }
+
// Task created by organizer are added as root.
final Task launchRootTask = mCreatedByOrganizer
- ? null : tda.getLaunchRootTask(mWindowingMode, mActivityType, mActivityOptions);
+ ? null : tda.getLaunchRootTask(mWindowingMode, mActivityType, mActivityOptions,
+ mSourceTask, mLaunchFlags);
if (launchRootTask != null) {
// Since this task will be put into a root task, its windowingMode will be
// inherited.
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 4d85e7b..cda8c4b 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -27,6 +27,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -43,7 +44,6 @@
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
-import android.content.Intent;
import android.os.UserHandle;
import android.util.IntArray;
import android.util.Slog;
@@ -133,6 +133,11 @@
private final ArrayList<LaunchRootTaskDef> mLaunchRootTasks = new ArrayList<>();
/**
+ * A launch root task for activity launching with {@link FLAG_ACTIVITY_LAUNCH_ADJACENT} flag.
+ */
+ private Task mLaunchAdjacentFlagRootTask;
+
+ /**
* A focusable root task that is purposely to be positioned at the top. Although the root
* task may not have the topmost index, it is used as a preferred candidate to prevent being
* unable to resume target root task properly when there are other focusable always-on-top
@@ -1013,6 +1018,9 @@
if (mPreferredTopFocusableRootTask == rootTask) {
mPreferredTopFocusableRootTask = null;
}
+ if (mLaunchAdjacentFlagRootTask == rootTask) {
+ mLaunchAdjacentFlagRootTask = null;
+ }
mDisplayContent.releaseSelfIfNeeded();
onRootTaskOrderChanged(rootTask);
}
@@ -1047,11 +1055,11 @@
* Returns an existing root task compatible with the windowing mode and activity type or
* creates one if a compatible root task doesn't exist.
*
- * @see #getOrCreateRootTask(int, int, boolean, Intent, Task, ActivityOptions)
+ * @see #getOrCreateRootTask(int, int, boolean, Task, Task, ActivityOptions, int)
*/
Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop) {
- return getOrCreateRootTask(windowingMode, activityType, onTop, null /* intent */,
- null /* candidateTask */, null /* options */);
+ return getOrCreateRootTask(windowingMode, activityType, onTop, null /* candidateTask */,
+ null /* sourceTask */, null /* options */, 0 /* intent */);
}
/**
@@ -1060,11 +1068,21 @@
* For one level task, the candidate task would be reused to also be the root task or create
* a new root task if no candidate task.
*
+ * @param windowingMode The windowing mode the root task should be created in.
+ * @param activityType The activityType the root task should be created in.
+ * @param onTop If true the root task will be created at the top of the display,
+ * else at the bottom.
+ * @param candidateTask The possible task the activity might be launched in. Can be null.
+ * @param sourceTask The task requesting to start activity. Used to determine which of the
+ * adjacent roots should be launch root of the new task. Can be null.
+ * @param options The activity options used to the launch. Can be null.
+ * @param launchFlags The launch flags for this launch.
+ * @return The root task to use for the launch.
* @see #getRootTask(int, int)
- * @see #createRootTask(int, int, boolean)
*/
Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop,
- Intent intent, Task candidateTask, ActivityOptions options) {
+ @Nullable Task candidateTask, @Nullable Task sourceTask,
+ @Nullable ActivityOptions options, int launchFlags) {
// Need to pass in a determined windowing mode to see if a new root task should be created,
// so use its parent's windowing mode if it is undefined.
if (!alwaysCreateRootTask(
@@ -1077,7 +1095,8 @@
} else if (candidateTask != null) {
final Task rootTask = candidateTask;
final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
- final Task launchRootTask = getLaunchRootTask(windowingMode, activityType, options);
+ final Task launchRootTask = getLaunchRootTask(windowingMode, activityType, options,
+ sourceTask, launchFlags);
if (launchRootTask != null) {
if (rootTask.getParent() == null) {
@@ -1103,8 +1122,9 @@
.setActivityType(activityType)
.setOnTop(onTop)
.setParent(this)
- .setIntent(intent)
+ .setSourceTask(sourceTask)
.setActivityOptions(options)
+ .setLaunchFlags(launchFlags)
.build();
}
@@ -1114,9 +1134,9 @@
*
* @see #getOrCreateRootTask(int, int, boolean)
*/
- Task getOrCreateRootTask(@Nullable ActivityRecord r,
- @Nullable ActivityOptions options, @Nullable Task candidateTask,
- @Nullable LaunchParams launchParams, int activityType, boolean onTop) {
+ Task getOrCreateRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+ @Nullable Task candidateTask, @Nullable Task sourceTask,
+ @Nullable LaunchParams launchParams, int launchFlags, int activityType, boolean onTop) {
int windowingMode = WINDOWING_MODE_UNDEFINED;
if (launchParams != null) {
// If launchParams isn't null, windowing mode is already resolved.
@@ -1130,8 +1150,8 @@
// UNDEFINED windowing mode is a valid result and means that the new root task will inherit
// it's display's windowing mode.
windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
- return getOrCreateRootTask(windowingMode, activityType, onTop, null /* intent */,
- candidateTask, options);
+ return getOrCreateRootTask(windowingMode, activityType, onTop, candidateTask, sourceTask,
+ options, launchFlags);
}
@VisibleForTesting
@@ -1199,6 +1219,24 @@
}
}
+ void setLaunchAdjacentFlagRootTask(@Nullable Task adjacentFlagRootTask) {
+ if (adjacentFlagRootTask != null) {
+ if (!adjacentFlagRootTask.mCreatedByOrganizer) {
+ throw new IllegalArgumentException(
+ "Can't set not mCreatedByOrganizer as launch adjacent flag root tr="
+ + adjacentFlagRootTask);
+ }
+
+ if (adjacentFlagRootTask.mAdjacentTask == null) {
+ throw new UnsupportedOperationException(
+ "Can't set non-adjacent root as launch adjacent flag root tr="
+ + adjacentFlagRootTask);
+ }
+ }
+
+ mLaunchAdjacentFlagRootTask = adjacentFlagRootTask;
+ }
+
private @Nullable LaunchRootTaskDef getLaunchRootTaskDef(Task rootTask) {
LaunchRootTaskDef def = null;
for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
@@ -1209,7 +1247,9 @@
return def;
}
- Task getLaunchRootTask(int windowingMode, int activityType, ActivityOptions options) {
+ @Nullable
+ Task getLaunchRootTask(int windowingMode, int activityType, @Nullable ActivityOptions options,
+ @Nullable Task sourceTask, int launchFlags) {
// Try to use the launch root task in options if available.
if (options != null) {
final Task launchRootTask = Task.fromWindowContainerToken(options.getLaunchRootTask());
@@ -1219,6 +1259,19 @@
}
}
+ // Use launch-adjacent-flag-root if launching with launch-adjacent flag.
+ if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0
+ && mLaunchAdjacentFlagRootTask != null) {
+ // If the adjacent launch is coming from the same root, launch to adjacent root instead.
+ if (sourceTask != null
+ && sourceTask.getRootTask().mTaskId == mLaunchAdjacentFlagRootTask.mTaskId
+ && mLaunchAdjacentFlagRootTask.mAdjacentTask != null) {
+ return mLaunchAdjacentFlagRootTask.mAdjacentTask;
+ } else {
+ return mLaunchAdjacentFlagRootTask;
+ }
+ }
+
for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
if (mLaunchRootTasks.get(i).contains(windowingMode, activityType)) {
return mLaunchRootTasks.get(i).task;
@@ -1963,7 +2016,11 @@
// Reparent task to corresponding launch root or display area.
final WindowContainer launchRoot = task.supportsSplitScreenWindowingMode()
? toDisplayArea.getLaunchRootTask(
- task.getWindowingMode(), task.getActivityType(), null /* options */)
+ task.getWindowingMode(),
+ task.getActivityType(),
+ null /* options */,
+ null /* sourceTask */,
+ 0 /* launchFlags */)
: null;
task.reparent(launchRoot == null ? toDisplayArea : launchRoot, POSITION_TOP);
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 625cff3..29677b2 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -292,7 +292,8 @@
mSupervisor.mRootWindowContainer.resolveActivityType(root, options, task);
display.forAllTaskDisplayAreas(displayArea -> {
final Task launchRoot = displayArea.getLaunchRootTask(
- resolvedMode, activityType, null /* ActivityOptions */);
+ resolvedMode, activityType, null /* ActivityOptions */,
+ null /* sourceTask*/, 0 /* launchFlags */);
if (launchRoot == null) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
index 1779d2a..7e992ac 100644
--- a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
+++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
@@ -17,8 +17,8 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
+import android.graphics.GraphicBuffer;
import android.hardware.HardwareBuffer;
-import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -51,14 +51,14 @@
task, mWidth, mHeight);
mSurfaceControl = surfaceControlFactory.apply(new SurfaceSession())
.setName("RecentTaskScreenshotSurface")
- .setBufferSize(mWidth, mHeight)
+ .setBLASTLayer()
.setCallsite("TaskScreenshotAnimatable")
.build();
if (buffer != null) {
- final Surface surface = new Surface();
- surface.copyFrom(mSurfaceControl);
- surface.attachAndQueueBufferWithColorSpace(buffer, screenshotBuffer.getColorSpace());
- surface.release();
+ GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(buffer);
+ getPendingTransaction().setBuffer(mSurfaceControl, graphicBuffer);
+ getPendingTransaction().setColorSpace(mSurfaceControl,
+ screenshotBuffer.getColorSpace());
final float scale = 1.0f * mTask.getBounds().width() / mWidth;
getPendingTransaction().setMatrix(mSurfaceControl, scale, 0, 0, scale);
}
diff --git a/services/core/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java
index 7f28ffc..66ab094 100644
--- a/services/core/java/com/android/server/wm/Watermark.java
+++ b/services/core/java/com/android/server/wm/Watermark.java
@@ -18,30 +18,26 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.graphics.BLASTBufferQueue;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
-import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
-import android.view.Display;
-import android.view.InputWindowHandle;
import android.view.Surface;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
-import java.util.function.Supplier;
-
/**
* Displays a watermark on top of the window manager's windows.
*/
class Watermark {
- private final Display mDisplay;
- private final String[] mTokens;
+ private static final String TITLE = "WatermarkSurface";
+
private final String mText;
private final Paint mTextPaint;
private final int mTextWidth;
@@ -51,28 +47,26 @@
private final SurfaceControl mSurfaceControl;
private final Surface mSurface;
+ private final BLASTBufferQueue mBlastBufferQueue;
+
private int mLastDW;
private int mLastDH;
private boolean mDrawNeeded;
- Watermark(Supplier<Surface> surfaceFactory, DisplayContent dc, DisplayMetrics dm,
- String[] tokens, SurfaceControl.Transaction t) {
+ Watermark(DisplayContent dc, DisplayMetrics dm, String[] tokens, SurfaceControl.Transaction t) {
if (false) {
Log.i(TAG_WM, "*********************** WATERMARK");
for (int i=0; i<tokens.length; i++) {
Log.i(TAG_WM, " TOKEN #" + i + ": " + tokens[i]);
}
}
- mSurface = surfaceFactory.get();
- mDisplay = dc.getDisplay();
- mTokens = tokens;
StringBuilder builder = new StringBuilder(32);
- int len = mTokens[0].length();
+ int len = tokens[0].length();
len = len & ~1;
for (int i=0; i<len; i+=2) {
- int c1 = mTokens[0].charAt(i);
- int c2 = mTokens[0].charAt(i+1);
+ int c1 = tokens[0].charAt(i);
+ int c2 = tokens[0].charAt(i + 1);
if (c1 >= 'a' && c1 <= 'f') c1 = c1 - 'a' + 10;
else if (c1 >= 'A' && c1 <= 'F') c1 = c1 - 'A' + 10;
else c1 -= '0';
@@ -118,20 +112,22 @@
SurfaceControl ctrl = null;
try {
ctrl = dc.makeOverlay()
- .setName("WatermarkSurface")
- .setBufferSize(1, 1)
+ .setName(TITLE)
+ .setBLASTLayer()
.setFormat(PixelFormat.TRANSLUCENT)
- .setCallsite("Watermark")
+ .setCallsite(TITLE)
.build();
t.setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 100)
.setPosition(ctrl, 0, 0)
.show(ctrl);
// Ensure we aren't considered as obscuring for Input purposes.
- InputMonitor.setTrustedOverlayInputInfo(ctrl, t, dc.getDisplayId(), "Watermark");
- mSurface.copyFrom(ctrl);
+ InputMonitor.setTrustedOverlayInputInfo(ctrl, t, dc.getDisplayId(), TITLE);
} catch (OutOfResourcesException e) {
}
mSurfaceControl = ctrl;
+ mBlastBufferQueue = new BLASTBufferQueue(TITLE, mSurfaceControl, 1 /* width */,
+ 1 /* height */, PixelFormat.RGBA_8888);
+ mSurface = mBlastBufferQueue.createSurface();
}
void positionSurface(int dw, int dh, SurfaceControl.Transaction t) {
@@ -144,45 +140,46 @@
}
void drawIfNeeded() {
- if (mDrawNeeded) {
- final int dw = mLastDW;
- final int dh = mLastDH;
+ if (!mDrawNeeded) {
+ return;
+ }
- mDrawNeeded = false;
- Rect dirty = new Rect(0, 0, dw, dh);
- Canvas c = null;
- try {
- c = mSurface.lockCanvas(dirty);
- } catch (IllegalArgumentException e) {
- } catch (Surface.OutOfResourcesException e) {
+ final int dw = mLastDW;
+ final int dh = mLastDH;
+
+ mDrawNeeded = false;
+ mBlastBufferQueue.update(mSurfaceControl, dw, dh, PixelFormat.RGBA_8888);
+ Canvas c = null;
+ try {
+ c = mSurface.lockCanvas(null);
+ } catch (IllegalArgumentException | OutOfResourcesException e) {
+ }
+ if (c != null) {
+ c.drawColor(0, PorterDuff.Mode.CLEAR);
+
+ int deltaX = mDeltaX;
+ int deltaY = mDeltaY;
+
+ // deltaX shouldn't be close to a round fraction of our
+ // x step, or else things will line up too much.
+ int div = (dw + mTextWidth) / deltaX;
+ int rem = (dw + mTextWidth) - (div * deltaX);
+ int qdelta = deltaX / 4;
+ if (rem < qdelta || rem > (deltaX - qdelta)) {
+ deltaX += deltaX / 3;
}
- if (c != null) {
- c.drawColor(0, PorterDuff.Mode.CLEAR);
- int deltaX = mDeltaX;
- int deltaY = mDeltaY;
-
- // deltaX shouldn't be close to a round fraction of our
- // x step, or else things will line up too much.
- int div = (dw+mTextWidth)/deltaX;
- int rem = (dw+mTextWidth) - (div*deltaX);
- int qdelta = deltaX/4;
- if (rem < qdelta || rem > (deltaX-qdelta)) {
- deltaX += deltaX/3;
+ int y = -mTextHeight;
+ int x = -mTextWidth;
+ while (y < (dh + mTextHeight)) {
+ c.drawText(mText, x, y, mTextPaint);
+ x += deltaX;
+ if (x >= dw) {
+ x -= (dw + mTextWidth);
+ y += deltaY;
}
-
- int y = -mTextHeight;
- int x = -mTextWidth;
- while (y < (dh+mTextHeight)) {
- c.drawText(mText, x, y, mTextPaint);
- x += deltaX;
- if (x >= dw) {
- x -= (dw+mTextWidth);
- y += deltaY;
- }
- }
- mSurface.unlockCanvasAndPost(c);
}
+ mSurface.unlockCanvasAndPost(c);
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
index b9f67a5..7f21eeb 100644
--- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
+++ b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
@@ -28,12 +28,13 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
+import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.HardwareBuffer;
import android.os.Process;
import android.util.proto.ProtoOutputStream;
-import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Builder;
import android.view.SurfaceControl.Transaction;
@@ -43,8 +44,6 @@
import com.android.server.wm.SurfaceAnimator.Animatable;
import com.android.server.wm.SurfaceAnimator.AnimationType;
-import java.util.function.Supplier;
-
/**
* Represents a surface that is displayed over a subclass of {@link WindowContainer}
*/
@@ -57,30 +56,20 @@
private final SurfaceAnimator mSurfaceAnimator;
private final int mWidth;
private final int mHeight;
- private final boolean mRelative;
-
- WindowContainerThumbnail(Supplier<Surface> surfaceFactory, Transaction t,
- WindowContainer container, HardwareBuffer thumbnailHeader) {
- this(surfaceFactory, t, container, thumbnailHeader, false /* relative */);
- }
/**
* @param t Transaction to create the thumbnail in.
* @param container The sub-class of {@link WindowContainer} to associate this thumbnail with.
* @param thumbnailHeader A thumbnail or placeholder for thumbnail to initialize with.
- * @param relative Whether this thumbnail will be a child of the container (and thus positioned
- * relative to it) or not.
*/
- WindowContainerThumbnail(Supplier<Surface> surfaceFactory, Transaction t,
- WindowContainer container, HardwareBuffer thumbnailHeader, boolean relative) {
- this(t, container, thumbnailHeader, relative, surfaceFactory.get(), null);
+ WindowContainerThumbnail(Transaction t, WindowContainer container,
+ HardwareBuffer thumbnailHeader) {
+ this(t, container, thumbnailHeader, null /* animator */);
}
WindowContainerThumbnail(Transaction t, WindowContainer container,
- HardwareBuffer thumbnailHeader, boolean relative, Surface drawSurface,
- SurfaceAnimator animator) {
+ HardwareBuffer thumbnailHeader, SurfaceAnimator animator) {
mWindowContainer = container;
- mRelative = relative;
if (animator != null) {
mSurfaceAnimator = animator;
} else {
@@ -99,7 +88,7 @@
// this to the task.
mSurfaceControl = mWindowContainer.makeChildSurface(mWindowContainer.getTopChild())
.setName("thumbnail anim: " + mWindowContainer.toString())
- .setBufferSize(mWidth, mHeight)
+ .setBLASTLayer()
.setFormat(PixelFormat.TRANSLUCENT)
.setMetadata(METADATA_WINDOW_TYPE, mWindowContainer.getWindowingMode())
.setMetadata(METADATA_OWNER_UID, Process.myUid())
@@ -108,18 +97,14 @@
ProtoLog.i(WM_SHOW_TRANSACTIONS, " THUMBNAIL %s: CREATE", mSurfaceControl);
- // Transfer the thumbnail to the surface
- drawSurface.copyFrom(mSurfaceControl);
- drawSurface.attachAndQueueBufferWithColorSpace(thumbnailHeader, null);
- drawSurface.release();
+ GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(thumbnailHeader);
+ t.setBuffer(mSurfaceControl, graphicBuffer);
+ t.setColorSpace(mSurfaceControl, ColorSpace.get(ColorSpace.Named.SRGB));
t.show(mSurfaceControl);
// We parent the thumbnail to the container, and just place it on top of anything else in
// the container.
t.setLayer(mSurfaceControl, Integer.MAX_VALUE);
- if (relative) {
- t.reparent(mSurfaceControl, mWindowContainer.getSurfaceControl());
- }
}
void startAnimation(Transaction t, Animation anim) {
@@ -194,9 +179,6 @@
@Override
public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
t.setLayer(leash, Integer.MAX_VALUE);
- if (mRelative) {
- t.reparent(leash, mWindowContainer.getSurfaceControl());
- }
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java
index 015a0fb..a5ebf9a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerConstants.java
+++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java
@@ -49,10 +49,6 @@
static final String KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS =
"system_gesture_exclusion_log_debounce_millis";
- // Enable logging from the sensor which publishes accel and gyro data generating a rotation
- // event
- private static final String KEY_RAW_SENSOR_LOGGING_ENABLED = "raw_sensor_logging_enabled";
-
private static final int MIN_GESTURE_EXCLUSION_LIMIT_DP = 200;
/** @see #KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS */
@@ -62,8 +58,6 @@
/** @see AndroidDeviceConfig#KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE */
boolean mSystemGestureExcludedByPreQStickyImmersive;
- boolean mRawSensorLoggingEnabled;
-
private final WindowManagerGlobalLock mGlobalLock;
private final Runnable mUpdateSystemGestureExclusionCallback;
private final DeviceConfigInterface mDeviceConfig;
@@ -139,9 +133,6 @@
case KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS:
updateSystemGestureExclusionLogDebounceMillis();
break;
- case KEY_RAW_SENSOR_LOGGING_ENABLED:
- updateRawSensorDataLoggingEnabled();
- break;
default:
break;
}
@@ -167,12 +158,6 @@
KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
}
- private void updateRawSensorDataLoggingEnabled() {
- mRawSensorLoggingEnabled = DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_WINDOW_MANAGER,
- KEY_RAW_SENSOR_LOGGING_ENABLED, false);
- }
-
void dump(PrintWriter pw) {
pw.println("WINDOW MANAGER CONSTANTS (dumpsys window constants):");
@@ -182,8 +167,6 @@
pw.print("="); pw.println(mSystemGestureExclusionLimitDp);
pw.print(" "); pw.print(KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE);
pw.print("="); pw.println(mSystemGestureExcludedByPreQStickyImmersive);
- pw.print(" "); pw.print(KEY_RAW_SENSOR_LOGGING_ENABLED);
- pw.print("="); pw.println(mRawSensorLoggingEnabled);
pw.println();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 12c9b97..9e8b6a3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -451,8 +451,7 @@
private static final int ANIMATION_COMPLETED_TIMEOUT_MS = 5000;
- @VisibleForTesting
- WindowManagerConstants mConstants;
+ final WindowManagerConstants mConstants;
final WindowTracing mWindowTracing;
@@ -3659,7 +3658,7 @@
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> showEmulatorDisplayOverlay");
if (mEmulatorDisplayOverlay == null) {
- mEmulatorDisplayOverlay = new EmulatorDisplayOverlay(mSurfaceFactory, mContext,
+ mEmulatorDisplayOverlay = new EmulatorDisplayOverlay(mContext,
getDefaultDisplayContentLocked(),
mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_POINTER)
* TYPE_LAYER_MULTIPLIER + 10, mTransaction);
@@ -3699,8 +3698,8 @@
// b/31532461
// TODO(multi-display): support multiple displays
if (mStrictModeFlash == null) {
- mStrictModeFlash = new StrictModeFlash(mSurfaceFactory,
- getDefaultDisplayContentLocked(), mTransaction);
+ mStrictModeFlash = new StrictModeFlash(getDefaultDisplayContentLocked(),
+ mTransaction);
}
mStrictModeFlash.setVisibility(on, mTransaction);
mTransaction.apply();
@@ -5554,11 +5553,6 @@
mBlurController.unregisterCrossWindowBlurEnabledListener(listener);
}
- @Override
- public void setForceCrossWindowBlurDisabled(boolean disable) {
- mBlurController.setForceCrossWindowBlurDisabled(disable);
- }
-
// -------------------------------------------------------------
// Internals
// -------------------------------------------------------------
@@ -5895,8 +5889,8 @@
if (toks != null && toks.length > 0) {
// TODO(multi-display): Show watermarks on secondary displays.
final DisplayContent displayContent = getDefaultDisplayContentLocked();
- mWatermark = new Watermark(mSurfaceFactory, displayContent,
- displayContent.mRealDisplayMetrics, toks, mTransaction);
+ mWatermark = new Watermark(displayContent, displayContent.mRealDisplayMetrics,
+ toks, mTransaction);
mTransaction.apply();
}
}
@@ -6298,7 +6292,7 @@
}
});
pw.print(" mInTouchMode="); pw.println(mInTouchMode);
- pw.print(" mBlurEnabled="); pw.println(mBlurController.mBlurEnabled);
+ pw.print(" mBlurEnabled="); pw.println(mBlurController.getBlurEnabled());
pw.print(" mLastDisplayFreezeDuration=");
TimeUtils.formatDuration(mLastDisplayFreezeDuration, pw);
if ( mLastFinishedFreezeSource != null) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 1b578d1..4dc6007 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -31,6 +31,7 @@
import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Pair;
import android.view.Display;
@@ -216,7 +217,7 @@
String arg = getNextArg();
if (arg == null) {
pw.println("Blur supported on device: " + CROSS_WINDOW_BLUR_SUPPORTED);
- pw.println("Blur enabled: " + mInternal.mBlurController.mBlurEnabled);
+ pw.println("Blur enabled: " + mInternal.mBlurController.getBlurEnabled());
return 0;
}
@@ -235,7 +236,9 @@
return -1;
}
- mInterface.setForceCrossWindowBlurDisabled(disableBlur);
+ Settings.Global.putInt(mInternal.mContext.getContentResolver(),
+ Settings.Global.DISABLE_WINDOW_BLURS, disableBlur ? 1 : 0);
+
return 0;
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 9382b8e..c29211f 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -22,6 +22,7 @@
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
@@ -320,6 +321,26 @@
}
break;
}
+ case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: {
+ final WindowContainer wc = WindowContainer.fromBinder(
+ hop.getContainer());
+ final Task task = wc != null ? wc.asTask() : null;
+ if (task == null) {
+ throw new IllegalArgumentException("Cannot set "
+ + "non-task as launch root: " + wc);
+ } else if (!task.mCreatedByOrganizer) {
+ throw new UnsupportedOperationException("Cannot set "
+ + "non-organized task as adjacent flag root: " + wc);
+ } else if (task.mAdjacentTask == null) {
+ throw new UnsupportedOperationException("Cannot set "
+ + "non-adjacent task as adjacent flag root: " + wc);
+ }
+
+ final boolean clearRoot = hop.getToTop();
+ task.getDisplayArea()
+ .setLaunchAdjacentFlagRootTask(clearRoot ? null : task);
+ break;
+ }
case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT:
effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId);
break;
@@ -491,7 +512,7 @@
Rect enterPipBounds = c.getEnterPipBounds();
if (enterPipBounds != null) {
- mService.mTaskSupervisor.updatePictureInPictureMode(tr, enterPipBounds, true);
+ tr.mDisplayContent.mPinnedTaskController.setEnterPipBounds(enterPipBounds);
}
return effects;
diff --git a/services/core/java/com/android/server/wm/WindowOrientationListener.java b/services/core/java/com/android/server/wm/WindowOrientationListener.java
index be6847ab..3e099fb 100644
--- a/services/core/java/com/android/server/wm/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/wm/WindowOrientationListener.java
@@ -85,7 +85,6 @@
private int mCurrentRotation = -1;
private final Context mContext;
- private final WindowManagerConstants mConstants;
private final Object mLock = new Object();
@@ -94,11 +93,9 @@
*
* @param context for the WindowOrientationListener.
* @param handler Provides the Looper for receiving sensor updates.
- * @param wmService WindowManagerService to read the device config from.
*/
- public WindowOrientationListener(
- Context context, Handler handler, WindowManagerService wmService) {
- this(context, handler, wmService, SensorManager.SENSOR_DELAY_UI);
+ public WindowOrientationListener(Context context, Handler handler) {
+ this(context, handler, SensorManager.SENSOR_DELAY_UI);
}
/**
@@ -115,10 +112,9 @@
* This constructor is private since no one uses it.
*/
private WindowOrientationListener(
- Context context, Handler handler, WindowManagerService wmService, int rate) {
+ Context context, Handler handler, int rate) {
mContext = context;
mHandler = handler;
- mConstants = wmService.mConstants;
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
mRate = rate;
List<Sensor> l = mSensorManager.getSensorList(Sensor.TYPE_DEVICE_ORIENTATION);
@@ -1134,16 +1130,11 @@
return;
}
- // Log raw sensor rotation.
- if (evaluateRotationChangeLocked() >= 0) {
- if (mConstants.mRawSensorLoggingEnabled) {
- FrameworkStatsLog.write(
- FrameworkStatsLog.DEVICE_ROTATED,
- event.timestamp,
- rotationToLogEnum(reportedRotation),
- FrameworkStatsLog.DEVICE_ROTATED__ROTATION_EVENT_TYPE__ACTUAL_EVENT);
- }
- }
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.DEVICE_ROTATED,
+ event.timestamp,
+ rotationToLogEnum(reportedRotation),
+ FrameworkStatsLog.DEVICE_ROTATED__ROTATION_EVENT_TYPE__ACTUAL_EVENT);
if (isRotationResolverEnabled()) {
if (mRotationResolverService == null) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 83f74cd..2e8d4cd 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -906,6 +906,12 @@
// The transform of its surface is handled by fixed rotation.
return;
}
+ final Task task = getTask();
+ if (task != null && task.inPinnedWindowingMode()) {
+ // It is handled by PinnedTaskController. Note that the windowing mode of activity
+ // and windows may still be fullscreen.
+ return;
+ }
if (mPendingSeamlessRotate != null) {
oldRotation = mPendingSeamlessRotate.getOldRotation();
@@ -1259,7 +1265,7 @@
mHaveFrame = true;
final Task task = getTask();
- final boolean isFullscreenAndFillsDisplay = !inMultiWindowMode() && matchesDisplayBounds();
+ final boolean isFullscreenAndFillsArea = !inMultiWindowMode() && matchesDisplayAreaBounds();
final boolean windowsAreFloating = task != null && task.isFloating();
final DisplayContent dc = getDisplayContent();
final DisplayInfo displayInfo = getDisplayInfo();
@@ -1284,7 +1290,7 @@
: isImeLayeringTarget();
final boolean isImeTarget =
imeWin != null && imeWin.isVisibleNow() && isInputMethodAdjustTarget;
- if (isFullscreenAndFillsDisplay || layoutInParentFrame()) {
+ if (isFullscreenAndFillsArea || layoutInParentFrame()) {
// We use the parent frame as the containing frame for fullscreen and child windows
windowFrames.mContainingFrame.set(windowFrames.mParentFrame);
layoutDisplayFrame = windowFrames.mDisplayFrame;
@@ -2266,19 +2272,15 @@
&& mWindowFrames.mFrame.bottom >= displayInfo.appHeight;
}
- private boolean matchesDisplayBounds() {
- final Rect displayBounds = mToken.getFixedRotationTransformDisplayBounds();
- if (displayBounds != null) {
- // If the rotated display bounds are available, the window bounds are also rotated.
- return displayBounds.equals(getBounds());
- }
- return getDisplayContent().getBounds().equals(getBounds());
- }
-
boolean matchesDisplayAreaBounds() {
+ final Rect rotatedDisplayBounds = mToken.getFixedRotationTransformDisplayBounds();
+ if (rotatedDisplayBounds != null) {
+ // If the rotated display bounds are available, the window bounds are also rotated.
+ return rotatedDisplayBounds.equals(getBounds());
+ }
final DisplayArea displayArea = getDisplayArea();
if (displayArea == null) {
- return matchesDisplayBounds();
+ return getDisplayContent().getBounds().equals(getBounds());
}
return displayArea.getBounds().equals(getBounds());
}
@@ -2292,6 +2294,27 @@
}
@Override
+ public void onConfigurationChanged(Configuration newParentConfig) {
+ if (getDisplayContent().getImeTarget(IME_TARGET_INPUT) != this && !isImeLayeringTarget()) {
+ super.onConfigurationChanged(newParentConfig);
+ return;
+ }
+
+ mTempConfiguration.setTo(getConfiguration());
+ super.onConfigurationChanged(newParentConfig);
+ final boolean windowConfigChanged = mTempConfiguration.windowConfiguration
+ .diff(newParentConfig.windowConfiguration, false) != 0;
+
+ // When the window configuration changed, we need to update the IME control target in
+ // case the app may lose the IME inets control when exiting from split-screen mode, or the
+ // IME parent may failed to attach to the app during rotating the screen.
+ // See DisplayContent#isImeAttachedToApp, DisplayContent#isImeControlledByApp
+ if (windowConfigChanged) {
+ getDisplayContent().updateImeControlTarget();
+ }
+ }
+
+ @Override
void onMergedOverrideConfigurationChanged() {
super.onMergedOverrideConfigurationChanged();
mLastConfigReportedToClient = false;
@@ -5348,7 +5371,8 @@
}
private boolean shouldDrawBlurBehind() {
- return (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 && mWmService.mBlurController.mBlurEnabled;
+ return (mAttrs.flags & FLAG_BLUR_BEHIND) != 0
+ && mWmService.mBlurController.getBlurEnabled();
}
/**
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index e4b9612..01834dd 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -48,6 +48,9 @@
<xs:element type="nonNegativeDecimal" name="screenBrightnessRampSlowIncrease">
<xs:annotation name="final"/>
</xs:element>
+ <xs:element type="sensorDetails" name="lightSensor">
+ <xs:annotation name="final"/>
+ </xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
@@ -119,4 +122,18 @@
<xs:minInclusive value="0.0"/>
</xs:restriction>
</xs:simpleType>
+
+ <xs:complexType name="sensorDetails">
+ <xs:sequence>
+ <xs:element type="xs:string" name="type" minOccurs="0" maxOccurs="1">
+ <xs:annotation name="nullable" />
+ <xs:annotation name="final"/>
+ </xs:element>
+ <xs:element type="xs:string" name="name" minOccurs="0" maxOccurs="1">
+ <xs:annotation name="nullable" />
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
</xs:schema>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index eb3f1b7..a848f82 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -4,6 +4,7 @@
public class DisplayConfiguration {
ctor public DisplayConfiguration();
method public com.android.server.display.config.HighBrightnessMode getHighBrightnessMode();
+ method public final com.android.server.display.config.SensorDetails getLightSensor();
method public com.android.server.display.config.DisplayQuirks getQuirks();
method @NonNull public final java.math.BigDecimal getScreenBrightnessDefault();
method @NonNull public final com.android.server.display.config.NitsMap getScreenBrightnessMap();
@@ -12,6 +13,7 @@
method public final java.math.BigDecimal getScreenBrightnessRampSlowDecrease();
method public final java.math.BigDecimal getScreenBrightnessRampSlowIncrease();
method public void setHighBrightnessMode(com.android.server.display.config.HighBrightnessMode);
+ method public final void setLightSensor(com.android.server.display.config.SensorDetails);
method public void setQuirks(com.android.server.display.config.DisplayQuirks);
method public final void setScreenBrightnessDefault(@NonNull java.math.BigDecimal);
method public final void setScreenBrightnessMap(@NonNull com.android.server.display.config.NitsMap);
@@ -61,6 +63,14 @@
method public final void setValue(@NonNull java.math.BigDecimal);
}
+ public class SensorDetails {
+ ctor public SensorDetails();
+ method @Nullable public final String getName();
+ method @Nullable public final String getType();
+ method public final void setName(@Nullable String);
+ method public final void setType(@Nullable String);
+ }
+
public class XmlParser {
ctor public XmlParser();
method public static com.android.server.display.config.DisplayConfiguration read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 66f47c6..d9fa471 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -108,7 +108,6 @@
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
-import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.provider.Telephony.Carriers.DPC_URI;
@@ -227,6 +226,7 @@
import android.media.AudioManager;
import android.media.IAudioService;
import android.net.ConnectivityManager;
+import android.net.ConnectivitySettingsManager;
import android.net.IIpConnectivityMetrics;
import android.net.ProxyInfo;
import android.net.Uri;
@@ -4516,8 +4516,7 @@
PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(parentUser);
final List<PasswordValidationError> passwordValidationErrors =
- PasswordMetrics.validatePasswordMetrics(
- minMetrics, complexity, false, metrics);
+ PasswordMetrics.validatePasswordMetrics(minMetrics, complexity, metrics);
isSufficient = passwordValidationErrors.isEmpty();
}
DevicePolicyEventLogger
@@ -4594,7 +4593,7 @@
maxRequiredComplexity = Math.max(maxRequiredComplexity, admin.mPasswordComplexity);
}
return PasswordMetrics.validatePasswordMetrics(PasswordMetrics.merge(adminMetrics),
- maxRequiredComplexity, false, metrics).isEmpty();
+ maxRequiredComplexity, metrics).isEmpty();
}
}
@@ -4630,8 +4629,7 @@
final int complexity = getAggregatedPasswordComplexityLocked(userId);
PasswordMetrics minMetrics = getPasswordMinimumMetricsUnchecked(userId);
final List<PasswordValidationError> passwordValidationErrors =
- PasswordMetrics.validatePasswordMetrics(
- minMetrics, complexity, false, metrics);
+ PasswordMetrics.validatePasswordMetrics(minMetrics, complexity, metrics);
return passwordValidationErrors.isEmpty();
}
@@ -4978,8 +4976,7 @@
// TODO: Consider changing validation API to take LockscreenCredential.
if (password.isEmpty()) {
validationErrors = PasswordMetrics.validatePasswordMetrics(
- minMetrics, complexity, isPin,
- new PasswordMetrics(CREDENTIAL_TYPE_NONE));
+ minMetrics, complexity, new PasswordMetrics(CREDENTIAL_TYPE_NONE));
} else {
// TODO(b/120484642): remove getBytes() below
validationErrors = PasswordMetrics.validatePassword(
@@ -5468,7 +5465,7 @@
&& (isProfileOwner(caller) || isDeviceOwner(caller)))
|| (caller.hasPackage() && (isCallerDelegate || isCredentialManagementApp)));
if (isCredentialManagementApp) {
- Preconditions.checkCallAuthorization(isUserSelectable, "The credential "
+ Preconditions.checkCallAuthorization(!isUserSelectable, "The credential "
+ "management app is not allowed to install a user selectable key pair");
Preconditions.checkCallAuthorization(
isAliasInCredentialManagementAppPolicy(caller, alias),
@@ -15700,12 +15697,12 @@
return context.getResources().getString(R.string.config_managed_provisioning_package);
}
- private void putPrivateDnsSettings(@Nullable String mode, @Nullable String host) {
+ private void putPrivateDnsSettings(int mode, @Nullable String host) {
// Set Private DNS settings using system permissions, as apps cannot write
// to global settings.
mInjector.binderWithCleanCallingIdentity(() -> {
- mInjector.settingsGlobalPutString(PRIVATE_DNS_MODE, mode);
- mInjector.settingsGlobalPutString(PRIVATE_DNS_SPECIFIER, host);
+ ConnectivitySettingsManager.setPrivateDnsMode(mContext, mode);
+ ConnectivitySettingsManager.setPrivateDnsHostname(mContext, host);
});
}
@@ -15725,7 +15722,8 @@
throw new IllegalArgumentException(
"Host provided for opportunistic mode, but is not needed.");
}
- putPrivateDnsSettings(ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC, null);
+ putPrivateDnsSettings(ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC,
+ null);
return PRIVATE_DNS_SET_NO_ERROR;
case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
if (TextUtils.isEmpty(privateDnsHost)
@@ -15737,7 +15735,7 @@
// Connectivity check will have been performed in the DevicePolicyManager before
// the call here.
putPrivateDnsSettings(
- ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
+ ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
privateDnsHost);
return PRIVATE_DNS_SET_NO_ERROR;
default:
@@ -15755,13 +15753,13 @@
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(isDeviceOwner(caller));
- final String currentMode = ConnectivityManager.getPrivateDnsMode(mContext);
+ final int currentMode = ConnectivitySettingsManager.getPrivateDnsMode(mContext);
switch (currentMode) {
- case ConnectivityManager.PRIVATE_DNS_MODE_OFF:
+ case ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF:
return PRIVATE_DNS_MODE_OFF;
- case ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC:
+ case ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC:
return PRIVATE_DNS_MODE_OPPORTUNISTIC;
- case ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
+ case ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
}
@@ -16782,7 +16780,9 @@
provisioningParams.isKeepAccountMigrated(), callerPackage);
if (provisioningParams.isOrganizationOwnedProvisioning()) {
- setProfileOwnerOnOrgOwnedDeviceState(admin, userInfo.id, caller.getUserId());
+ synchronized (getLockObject()) {
+ markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id);
+ }
}
return userInfo.getUserHandle();
@@ -17014,22 +17014,6 @@
}
}
- private void setProfileOwnerOnOrgOwnedDeviceState(
- ComponentName admin, @UserIdInt int profileId, @UserIdInt int parentUserId) {
- synchronized (getLockObject()) {
- markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, profileId);
- }
- restrictRemovalOfManagedProfile(parentUserId);
- }
-
- private void restrictRemovalOfManagedProfile(@UserIdInt int parentUserId) {
- final UserHandle parentUserHandle = UserHandle.of(parentUserId);
- mUserManager.setUserRestriction(
- UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
- /* value= */ true,
- parentUserHandle);
- }
-
@Override
public void provisionFullyManagedDevice(
@NonNull FullyManagedDeviceProvisioningParams provisioningParams,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index a2db6aac..285ecfb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -15,12 +15,8 @@
*/
package com.android.server.devicepolicy;
-import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
import android.os.ShellCommand;
-import android.os.SystemClock;
-import android.os.UserHandle;
import com.android.server.devicepolicy.Owners.OwnerDto;
@@ -36,23 +32,8 @@
private static final String CMD_SET_SAFE_OPERATION = "set-operation-safe";
private static final String CMD_LIST_OWNERS = "list-owners";
private static final String CMD_LIST_POLICY_EXEMPT_APPS = "list-policy-exempt-apps";
- private static final String CMD_SET_ACTIVE_ADMIN = "set-active-admin";
- private static final String CMD_SET_DEVICE_OWNER = "set-device-owner";
- private static final String CMD_SET_PROFILE_OWNER = "set-profile-owner";
- private static final String CMD_REMOVE_ACTIVE_ADMIN = "remove-active-admin";
- private static final String CMD_CLEAR_FREEZE_PERIOD_RECORD = "clear-freeze-period-record";
- private static final String CMD_FORCE_NETWORK_LOGS = "force-network-logs";
- private static final String CMD_FORCE_SECURITY_LOGS = "force-security-logs";
- private static final String CMD_MARK_PO_ON_ORG_OWNED_DEVICE =
- "mark-profile-owner-on-organization-owned-device";
-
- private static final String USER_OPTION = "--user";
- private static final String NAME_OPTION = "--name";
private final DevicePolicyManagerService mService;
- private int mUserId = UserHandle.USER_SYSTEM;
- private String mName = "";
- private ComponentName mComponent;
DevicePolicyManagerServiceShellCommand(DevicePolicyManagerService service) {
mService = Objects.requireNonNull(service);
@@ -60,7 +41,7 @@
@Override
public void onHelp() {
- try (PrintWriter pw = getOutPrintWriter()) {
+ try (PrintWriter pw = getOutPrintWriter();) {
pw.printf("DevicePolicyManager Service (device_policy) commands:\n\n");
showHelp(pw);
}
@@ -71,7 +52,7 @@
if (cmd == null) {
return handleDefaultCommands(cmd);
}
- try (PrintWriter pw = getOutPrintWriter()) {
+ try (PrintWriter pw = getOutPrintWriter();) {
switch (cmd) {
case CMD_IS_SAFE_OPERATION:
return runIsSafeOperation(pw);
@@ -83,22 +64,6 @@
return runListOwners(pw);
case CMD_LIST_POLICY_EXEMPT_APPS:
return runListPolicyExemptApps(pw);
- case CMD_SET_ACTIVE_ADMIN:
- return runSetActiveAdmin(pw);
- case CMD_SET_DEVICE_OWNER:
- return runSetDeviceOwner(pw);
- case CMD_SET_PROFILE_OWNER:
- return runSetProfileOwner(pw);
- case CMD_REMOVE_ACTIVE_ADMIN:
- return runRemoveActiveAdmin(pw);
- case CMD_CLEAR_FREEZE_PERIOD_RECORD:
- return runClearFreezePeriodRecord(pw);
- case CMD_FORCE_NETWORK_LOGS:
- return runForceNetworkLogs(pw);
- case CMD_FORCE_SECURITY_LOGS:
- return runForceSecurityLogs(pw);
- case CMD_MARK_PO_ON_ORG_OWNED_DEVICE:
- return runMarkProfileOwnerOnOrganizationOwnedDevice(pw);
default:
return onInvalidCommand(pw, cmd);
}
@@ -110,7 +75,7 @@
return 0;
}
- pw.printf("Usage: \n");
+ pw.println("Usage: ");
showHelp(pw);
return -1;
}
@@ -129,37 +94,6 @@
pw.printf(" Lists the device / profile owners per user \n\n");
pw.printf(" %s\n", CMD_LIST_POLICY_EXEMPT_APPS);
pw.printf(" Lists the apps that are exempt from policies\n\n");
- pw.printf(" %s [ %s <USER_ID> | current ] <COMPONENT>\n",
- CMD_SET_ACTIVE_ADMIN, USER_OPTION);
- pw.printf(" Sets the given component as active admin for an existing user.\n\n");
- pw.printf(" %s [ %s <USER_ID> | current *EXPERIMENTAL* ] [ %s <NAME> ] "
- + "<COMPONENT>\n", CMD_SET_DEVICE_OWNER, USER_OPTION, NAME_OPTION);
- pw.printf(" Sets the given component as active admin, and its package as device owner."
- + "\n\n");
- pw.printf(" %s [ %s <USER_ID> | current ] [ %s <NAME> ] <COMPONENT>\n",
- CMD_SET_PROFILE_OWNER, USER_OPTION, NAME_OPTION);
- pw.printf(" Sets the given component as active admin and profile owner for an existing "
- + "user.\n\n");
- pw.printf(" %s [ %s <USER_ID> | current ] [ %s <NAME> ] <COMPONENT>\n",
- CMD_REMOVE_ACTIVE_ADMIN, USER_OPTION, NAME_OPTION);
- pw.printf(" Disables an active admin, the admin must have declared android:testOnly in "
- + "the application in its manifest. This will also remove device and profile "
- + "owners.\n\n");
- pw.printf(" %s\n", CMD_CLEAR_FREEZE_PERIOD_RECORD);
- pw.printf(" Clears framework-maintained record of past freeze periods that the device "
- + "went through. For use during feature development to prevent triggering "
- + "restriction on setting freeze periods.\n\n");
- pw.printf(" %s\n", CMD_FORCE_NETWORK_LOGS);
- pw.printf(" Makes all network logs available to the DPC and triggers "
- + "DeviceAdminReceiver.onNetworkLogsAvailable() if needed.\n\n");
- pw.printf(" %s\n", CMD_FORCE_SECURITY_LOGS);
- pw.printf(" Makes all security logs available to the DPC and triggers "
- + "DeviceAdminReceiver.onSecurityLogsAvailable() if needed.\n\n");
- pw.printf(" %s [ %s <USER_ID> | current ] <COMPONENT>\n",
- CMD_MARK_PO_ON_ORG_OWNED_DEVICE, USER_OPTION);
- pw.printf(" Marks the profile owner of the given user as managing an organization-owned"
- + "device. That will give it access to device identifiers (such as serial number, "
- + "IMEI and MEID), as well as other privileges.\n\n");
}
private int runIsSafeOperation(PrintWriter pw) {
@@ -227,6 +161,7 @@
return 0;
}
+
private int runListPolicyExemptApps(PrintWriter pw) {
List<String> apps = mService.listPolicyExemptApps();
int size = printAndGetSize(pw, apps, "policy exempt app");
@@ -239,131 +174,4 @@
}
return 0;
}
-
- private int runSetActiveAdmin(PrintWriter pw) {
- parseArgs(/* canHaveName= */ false);
- mService.setActiveAdmin(mComponent, /* refreshing= */ true, mUserId);
-
- pw.printf("Success: Active admin set to component %s\n", mComponent.flattenToShortString());
- return 0;
- }
-
- private int runSetDeviceOwner(PrintWriter pw) {
- parseArgs(/* canHaveName= */ true);
- mService.setActiveAdmin(mComponent, /* refreshing= */ true, mUserId);
-
- try {
- if (!mService.setDeviceOwner(mComponent, mName, mUserId)) {
- throw new RuntimeException(
- "Can't set package " + mComponent + " as device owner.");
- }
- } catch (Exception e) {
- // Need to remove the admin that we just added.
- mService.removeActiveAdmin(mComponent, UserHandle.USER_SYSTEM);
- throw e;
- }
-
- mService.setUserProvisioningState(
- DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId);
-
- pw.printf("Success: Device owner set to package %s\n", mComponent.flattenToShortString());
- pw.printf("Active admin set to component %s\n", mComponent.flattenToShortString());
- return 0;
- }
-
- private int runRemoveActiveAdmin(PrintWriter pw) {
- parseArgs(/* canHaveName= */ false);
- mService.forceRemoveActiveAdmin(mComponent, mUserId);
- pw.printf("Success: Admin removed %s\n", mComponent);
- return 0;
- }
-
- private int runSetProfileOwner(PrintWriter pw) {
- parseArgs(/* canHaveName= */ true);
- mService.setActiveAdmin(mComponent, /* refreshing= */ true, mUserId);
-
- try {
- if (!mService.setProfileOwner(mComponent, mName, mUserId)) {
- throw new RuntimeException("Can't set component "
- + mComponent.flattenToShortString() + " as profile owner for user "
- + mUserId);
- }
- } catch (Exception e) {
- // Need to remove the admin that we just added.
- mService.removeActiveAdmin(mComponent, mUserId);
- throw e;
- }
-
- mService.setUserProvisioningState(
- DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId);
-
- pw.printf("Success: Active admin and profile owner set to %s for user %d\n",
- mComponent.flattenToShortString(), mUserId);
- return 0;
- }
-
- private int runClearFreezePeriodRecord(PrintWriter pw) {
- mService.clearSystemUpdatePolicyFreezePeriodRecord();
- pw.printf("Success\n");
- return 0;
- }
-
- private int runForceNetworkLogs(PrintWriter pw) {
- while (true) {
- long toWait = mService.forceNetworkLogs();
- if (toWait == 0) {
- break;
- }
- pw.printf("We have to wait for %d milliseconds...\n", toWait);
- SystemClock.sleep(toWait);
- }
- pw.printf("Success\n");
- return 0;
- }
-
- private int runForceSecurityLogs(PrintWriter pw) {
- while (true) {
- long toWait = mService.forceSecurityLogs();
- if (toWait == 0) {
- break;
- }
- pw.printf("We have to wait for %d milliseconds...\n", toWait);
- SystemClock.sleep(toWait);
- }
- pw.printf("Success\n");
- return 0;
- }
-
- private int runMarkProfileOwnerOnOrganizationOwnedDevice(PrintWriter pw) {
- parseArgs(/* canHaveName= */ false);
- mService.markProfileOwnerOnOrganizationOwnedDevice(mComponent, mUserId);
- pw.printf("Success\n");
- return 0;
- }
-
- private void parseArgs(boolean canHaveName) {
- String opt;
- while ((opt = getNextOption()) != null) {
- if (USER_OPTION.equals(opt)) {
- String arg = getNextArgRequired();
- mUserId = UserHandle.parseUserArg(arg);
- if (mUserId == UserHandle.USER_CURRENT) {
- mUserId = ActivityManager.getCurrentUser();
- }
- } else if (canHaveName && NAME_OPTION.equals(opt)) {
- mName = getNextArgRequired();
- } else {
- throw new IllegalArgumentException("Unknown option: " + opt);
- }
- }
- mComponent = parseComponentName(getNextArgRequired());
- }
-
- private ComponentName parseComponentName(String component) {
- ComponentName cn = ComponentName.unflattenFromString(component);
- if (cn == null) {
- throw new IllegalArgumentException("Invalid component " + component);
- }
- return cn;
- }
}
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 4ce336d..f3e7d67 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -2394,26 +2394,20 @@
}
void IncrementalService::getMetrics(StorageId storageId, android::os::PersistableBundle* result) {
- const auto duration = getMillsSinceOldestPendingRead(storageId);
- if (duration >= 0) {
- const auto kMetricsMillisSinceOldestPendingRead =
- os::incremental::BnIncrementalService::METRICS_MILLIS_SINCE_OLDEST_PENDING_READ();
- result->putLong(String16(kMetricsMillisSinceOldestPendingRead.data()), duration);
- }
-}
-
-long IncrementalService::getMillsSinceOldestPendingRead(StorageId storageId) {
const auto ifs = getIfs(storageId);
if (!ifs) {
- LOG(ERROR) << "getMillsSinceOldestPendingRead failed, invalid storageId: " << storageId;
- return -EINVAL;
+ LOG(ERROR) << "getMetrics failed, invalid storageId: " << storageId;
+ return;
}
+ const auto kMetricsReadLogsEnabled =
+ os::incremental::BnIncrementalService::METRICS_READ_LOGS_ENABLED();
+ result->putBoolean(String16(kMetricsReadLogsEnabled.data()), ifs->readLogsEnabled() != 0);
+
std::unique_lock l(ifs->lock);
if (!ifs->dataLoaderStub) {
- LOG(ERROR) << "getMillsSinceOldestPendingRead failed, no data loader: " << storageId;
- return -EINVAL;
+ return;
}
- return ifs->dataLoaderStub->elapsedMsSinceOldestPendingRead();
+ ifs->dataLoaderStub->getMetrics(result);
}
IncrementalService::DataLoaderStub::DataLoaderStub(
@@ -2660,9 +2654,6 @@
}
switch (targetStatus) {
- case IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE:
- // Do nothing, this is a reset state.
- break;
case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: {
switch (currentStatus) {
case IDataLoaderStatusListener::DATA_LOADER_BINDING:
@@ -2683,8 +2674,12 @@
}
case IDataLoaderStatusListener::DATA_LOADER_CREATED:
switch (currentStatus) {
- case IDataLoaderStatusListener::DATA_LOADER_DESTROYED:
case IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE:
+ case IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE:
+ // Before binding need to make sure we are unbound.
+ // Otherwise we'll get stuck binding.
+ return destroy();
+ case IDataLoaderStatusListener::DATA_LOADER_DESTROYED:
case IDataLoaderStatusListener::DATA_LOADER_BINDING:
return bind();
case IDataLoaderStatusListener::DATA_LOADER_BOUND:
@@ -2709,7 +2704,8 @@
<< ", but got: " << mountId;
return binder::Status::fromServiceSpecificError(-EPERM, "Mount ID mismatch.");
}
- if (newStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) {
+ if (newStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE ||
+ newStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) {
// User-provided status, let's postpone the handling to avoid possible deadlocks.
mService.addTimedJob(*mService.mTimedQueue, id(), Constants::userStatusDelay,
[this, newStatus]() { setCurrentStatus(newStatus); });
@@ -2721,7 +2717,7 @@
}
void IncrementalService::DataLoaderStub::setCurrentStatus(int newStatus) {
- int targetStatus, oldStatus;
+ int oldStatus, oldTargetStatus, newTargetStatus;
DataLoaderStatusListener listener;
{
std::unique_lock lock(mMutex);
@@ -2730,22 +2726,31 @@
}
oldStatus = mCurrentStatus;
- targetStatus = mTargetStatus;
+ oldTargetStatus = mTargetStatus;
listener = mStatusListener;
// Change the status.
mCurrentStatus = newStatus;
mCurrentStatusTs = mService.mClock->now();
- if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE ||
- mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) {
- // For unavailable, unbind from DataLoader to ensure proper re-commit.
- setTargetStatusLocked(IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
+ switch (mCurrentStatus) {
+ case IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE:
+ // Unavailable, retry.
+ setTargetStatusLocked(IDataLoaderStatusListener::DATA_LOADER_STARTED);
+ break;
+ case IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE:
+ // Unrecoverable, just unbind.
+ setTargetStatusLocked(IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
+ break;
+ default:
+ break;
}
+
+ newTargetStatus = mTargetStatus;
}
LOG(DEBUG) << "Current status update for DataLoader " << id() << ": " << oldStatus << " -> "
- << newStatus << " (target " << targetStatus << ")";
+ << newStatus << " (target " << oldTargetStatus << " -> " << newTargetStatus << ")";
if (listener) {
listener->onStatusChanged(id(), newStatus);
@@ -2767,6 +2772,7 @@
if (healthListener) {
healthListener->onHealthStatus(id(), healthStatus);
}
+ mHealthStatus = healthStatus;
}
void IncrementalService::DataLoaderStub::updateHealthStatus(bool baseline) {
@@ -2938,6 +2944,29 @@
return result;
}
+void IncrementalService::DataLoaderStub::getMetrics(android::os::PersistableBundle* result) {
+ const auto duration = elapsedMsSinceOldestPendingRead();
+ if (duration >= 0) {
+ const auto kMetricsMillisSinceOldestPendingRead =
+ os::incremental::BnIncrementalService::METRICS_MILLIS_SINCE_OLDEST_PENDING_READ();
+ result->putLong(String16(kMetricsMillisSinceOldestPendingRead.data()), duration);
+ }
+ const auto kMetricsStorageHealthStatusCode =
+ os::incremental::BnIncrementalService::METRICS_STORAGE_HEALTH_STATUS_CODE();
+ result->putInt(String16(kMetricsStorageHealthStatusCode.data()), mHealthStatus);
+ const auto kMetricsDataLoaderStatusCode =
+ os::incremental::BnIncrementalService::METRICS_DATA_LOADER_STATUS_CODE();
+ result->putInt(String16(kMetricsDataLoaderStatusCode.data()), mCurrentStatus);
+ const auto kMetricsMillisSinceLastDataLoaderBind =
+ os::incremental::BnIncrementalService::METRICS_MILLIS_SINCE_LAST_DATA_LOADER_BIND();
+ result->putLong(String16(kMetricsMillisSinceLastDataLoaderBind.data()),
+ (long)(elapsedMcs(mPreviousBindTs, mService.mClock->now()) / 1000));
+ const auto kMetricsDataLoaderBindDelayMillis =
+ os::incremental::BnIncrementalService::METRICS_DATA_LOADER_BIND_DELAY_MILLIS();
+ result->putLong(String16(kMetricsDataLoaderBindDelayMillis.data()),
+ (long)(mPreviousBindDelay.count()));
+}
+
long IncrementalService::DataLoaderStub::elapsedMsSinceOldestPendingRead() {
const auto oldestPendingReadKernelTs = getOldestTsFromLastPendingReads();
if (oldestPendingReadKernelTs == kMaxBootClockTsUs) {
@@ -3007,7 +3036,7 @@
dprintf(fd, " bootClockTsUs: %lld\n", (long long)pendingRead.bootClockTsUs);
}
dprintf(fd, " bind: %llds ago (delay: %llds)\n",
- (long long)(elapsedMcs(mPreviousBindTs, Clock::now()) / 1000000),
+ (long long)(elapsedMcs(mPreviousBindTs, mService.mClock->now()) / 1000000),
(long long)(mPreviousBindDelay.count() / 1000));
dprintf(fd, " }\n");
const auto& params = mParams;
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 95a17d1..8dc789f 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -249,7 +249,7 @@
bool isSystemDataLoader() const;
void setHealthListener(const StorageHealthCheckParams& healthCheckParams,
StorageHealthListener&& healthListener);
- long elapsedMsSinceOldestPendingRead();
+ void getMetrics(android::os::PersistableBundle* _aidl_return);
private:
binder::Status onStatusChanged(MountId mount, int newStatus) final;
@@ -281,6 +281,7 @@
BootClockTsUs getOldestPendingReadTs();
BootClockTsUs getOldestTsFromLastPendingReads();
Milliseconds elapsedMsSinceKernelTs(TimePoint now, BootClockTsUs kernelTsUs);
+ long elapsedMsSinceOldestPendingRead();
// If the stub has to bind to the DL.
// Returns {} if bind operation is already in progress.
@@ -298,6 +299,7 @@
content::pm::FileSystemControlParcel mControl;
DataLoaderStatusListener mStatusListener;
StorageHealthListener mHealthListener;
+ std::atomic<int> mHealthStatus = IStorageHealthListener::HEALTH_STATUS_OK;
std::condition_variable mStatusCondition;
int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
@@ -468,7 +470,6 @@
bool updateLoadingProgress(int32_t storageId,
StorageLoadingProgressListener&& progressListener);
- long getMillsSinceOldestPendingRead(StorageId storage);
void trimReservedSpaceV1(const IncFsMount& ifs);
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 6a3d953..68586a8 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -126,7 +126,7 @@
class MockDataLoader : public IDataLoader {
public:
MockDataLoader() {
- ON_CALL(*this, create(_, _, _, _)).WillByDefault(Invoke(this, &MockDataLoader::createOk));
+ initializeCreateOk();
ON_CALL(*this, start(_)).WillByDefault(Invoke(this, &MockDataLoader::startOk));
ON_CALL(*this, stop(_)).WillByDefault(Invoke(this, &MockDataLoader::stopOk));
ON_CALL(*this, destroy(_)).WillByDefault(Invoke(this, &MockDataLoader::destroyOk));
@@ -145,6 +145,10 @@
binder::Status(int32_t id, const std::vector<InstallationFileParcel>& addedFiles,
const std::vector<std::string>& removedFiles));
+ void initializeCreateOk() {
+ ON_CALL(*this, create(_, _, _, _)).WillByDefault(Invoke(this, &MockDataLoader::createOk));
+ }
+
void initializeCreateOkNoStatus() {
ON_CALL(*this, create(_, _, _, _))
.WillByDefault(Invoke(this, &MockDataLoader::createOkNoStatus));
@@ -275,6 +279,14 @@
}
return binder::Status::ok();
}
+ binder::Status bindToDataLoaderOkWithNoDelay(int32_t mountId,
+ const DataLoaderParamsParcel& params,
+ int bindDelayMs,
+ const sp<IDataLoaderStatusListener>& listener,
+ bool* _aidl_return) {
+ CHECK(bindDelayMs == 0) << bindDelayMs;
+ return bindToDataLoaderOk(mountId, params, bindDelayMs, listener, _aidl_return);
+ }
binder::Status bindToDataLoaderOkWith1sDelay(int32_t mountId,
const DataLoaderParamsParcel& params,
int bindDelayMs,
@@ -338,14 +350,13 @@
mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE);
}
binder::Status unbindFromDataLoaderOk(int32_t id) {
+ mBindDelayMs = -1;
if (mDataLoader) {
if (auto status = mDataLoader->destroy(id); !status.isOk()) {
return status;
}
mDataLoader = nullptr;
- }
- mBindDelayMs = -1;
- if (mListener) {
+ } else if (mListener) {
mListener->onStatusChanged(id, IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
}
return binder::Status::ok();
@@ -775,16 +786,53 @@
mDataLoaderManager->getDataLoaderSuccess();
}
- void checkMillisSinceOldestPendingRead(int storageId, long expected) {
+ void checkHealthMetrics(int storageId, long expectedMillisSinceOldestPendingRead,
+ int expectedStorageHealthStatusCode) {
android::os::PersistableBundle result{};
mIncrementalService->getMetrics(storageId, &result);
- int64_t value = -1;
+ ASSERT_EQ(6, (int)result.size());
+ int64_t millisSinceOldestPendingRead = -1;
ASSERT_TRUE(result.getLong(String16(BnIncrementalService::
METRICS_MILLIS_SINCE_OLDEST_PENDING_READ()
.c_str()),
- &value));
- ASSERT_EQ(expected, value);
- ASSERT_EQ(1, (int)result.size());
+ &millisSinceOldestPendingRead));
+ ASSERT_EQ(expectedMillisSinceOldestPendingRead, millisSinceOldestPendingRead);
+ int storageHealthStatusCode = -1;
+ ASSERT_TRUE(
+ result.getInt(String16(BnIncrementalService::METRICS_STORAGE_HEALTH_STATUS_CODE()
+ .c_str()),
+ &storageHealthStatusCode));
+ ASSERT_EQ(expectedStorageHealthStatusCode, storageHealthStatusCode);
+ int dataLoaderStatusCode = -1;
+ ASSERT_TRUE(result.getInt(String16(BnIncrementalService::METRICS_DATA_LOADER_STATUS_CODE()
+ .c_str()),
+ &dataLoaderStatusCode));
+ ASSERT_EQ(IDataLoaderStatusListener::DATA_LOADER_STARTED, dataLoaderStatusCode);
+ }
+
+ void checkBindingMetrics(int storageId, int64_t expectedMillisSinceLastDataLoaderBind,
+ int64_t expectedDataLoaderBindDelayMillis) {
+ android::os::PersistableBundle result{};
+ mIncrementalService->getMetrics(storageId, &result);
+ ASSERT_EQ(6, (int)result.size());
+ int dataLoaderStatus = -1;
+ ASSERT_TRUE(result.getInt(String16(BnIncrementalService::METRICS_DATA_LOADER_STATUS_CODE()
+ .c_str()),
+ &dataLoaderStatus));
+ ASSERT_EQ(IDataLoaderStatusListener::DATA_LOADER_STARTED, dataLoaderStatus);
+ int64_t millisSinceLastDataLoaderBind = -1;
+ ASSERT_TRUE(result.getLong(String16(BnIncrementalService::
+ METRICS_MILLIS_SINCE_LAST_DATA_LOADER_BIND()
+ .c_str()),
+ &millisSinceLastDataLoaderBind));
+ ASSERT_EQ(expectedMillisSinceLastDataLoaderBind, millisSinceLastDataLoaderBind);
+ int64_t dataLoaderBindDelayMillis = -1;
+ ASSERT_TRUE(
+ result.getLong(String16(
+ BnIncrementalService::METRICS_DATA_LOADER_BIND_DELAY_MILLIS()
+ .c_str()),
+ &dataLoaderBindDelayMillis));
+ ASSERT_EQ(expectedDataLoaderBindDelayMillis, dataLoaderBindDelayMillis);
}
protected:
@@ -904,38 +952,55 @@
ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
.WillByDefault(Invoke(mDataLoaderManager,
&MockDataLoaderManager::bindToDataLoaderOkWith1sDelay));
+ checkBindingMetrics(storageId, 0, 0);
mClock->advanceMs(mDataLoaderManager->bindDelayMs());
+ checkBindingMetrics(storageId, 0, 0);
mDataLoaderManager->setDataLoaderStatusDestroyed();
ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
.WillByDefault(Invoke(mDataLoaderManager,
&MockDataLoaderManager::bindToDataLoaderOkWith10sDelay));
+ checkBindingMetrics(storageId, 0, mDataLoaderManager->bindDelayMs());
mClock->advanceMs(mDataLoaderManager->bindDelayMs());
+ checkBindingMetrics(storageId, mDataLoaderManager->bindDelayMs(),
+ mDataLoaderManager->bindDelayMs());
mDataLoaderManager->setDataLoaderStatusDestroyed();
ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
.WillByDefault(Invoke(mDataLoaderManager,
&MockDataLoaderManager::bindToDataLoaderOkWith100sDelay));
+ checkBindingMetrics(storageId, 0, mDataLoaderManager->bindDelayMs());
mClock->advanceMs(mDataLoaderManager->bindDelayMs());
+ checkBindingMetrics(storageId, mDataLoaderManager->bindDelayMs(),
+ mDataLoaderManager->bindDelayMs());
mDataLoaderManager->setDataLoaderStatusDestroyed();
ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
.WillByDefault(Invoke(mDataLoaderManager,
&MockDataLoaderManager::bindToDataLoaderOkWith1000sDelay));
+ checkBindingMetrics(storageId, 0, mDataLoaderManager->bindDelayMs());
mClock->advanceMs(mDataLoaderManager->bindDelayMs());
+ checkBindingMetrics(storageId, mDataLoaderManager->bindDelayMs(),
+ mDataLoaderManager->bindDelayMs());
mDataLoaderManager->setDataLoaderStatusDestroyed();
ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
.WillByDefault(Invoke(mDataLoaderManager,
&MockDataLoaderManager::bindToDataLoaderOkWith10000sDelay));
+ checkBindingMetrics(storageId, 0, mDataLoaderManager->bindDelayMs());
// Try the reduced delay, just in case.
mClock->advanceMs(mDataLoaderManager->bindDelayMs() / 2);
+ checkBindingMetrics(storageId, mDataLoaderManager->bindDelayMs() / 2,
+ mDataLoaderManager->bindDelayMs());
mDataLoaderManager->setDataLoaderStatusDestroyed();
ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
.WillByDefault(Invoke(mDataLoaderManager,
&MockDataLoaderManager::bindToDataLoaderOkWith10000sDelay));
+ checkBindingMetrics(storageId, 0, mDataLoaderManager->bindDelayMs());
mClock->advanceMs(mDataLoaderManager->bindDelayMs());
+ checkBindingMetrics(storageId, mDataLoaderManager->bindDelayMs(),
+ mDataLoaderManager->bindDelayMs());
mDataLoaderManager->setDataLoaderStatusDestroyed();
}
@@ -1156,12 +1221,81 @@
ASSERT_GE(storageId, 0);
ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
{}, {}));
- mDataLoaderManager->setDataLoaderStatusUnavailable();
+ mDataLoaderManager->setDataLoaderStatusUnrecoverable();
+
+ // Timed callback present.
+ ASSERT_EQ(storageId, mTimedQueue->mId);
+ ASSERT_GE(mTimedQueue->mAfter, 10ms);
+ auto timedCallback = mTimedQueue->mWhat;
+ mTimedQueue->clearJob(storageId);
+
+ // First callback call to propagate unrecoverable.
+ timedCallback();
+
+ // And second call to trigger recreation.
ASSERT_NE(nullptr, mLooper->mCallback);
ASSERT_NE(nullptr, mLooper->mCallbackData);
mLooper->mCallback(-1, -1, mLooper->mCallbackData);
}
+TEST_F(IncrementalServiceTest, testStartDataLoaderUnavailable) {
+ mIncFs->openMountSuccess();
+ mDataLoader->initializeCreateOkNoStatus();
+
+ EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)).Times(3);
+ EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(3);
+ EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(3);
+ EXPECT_CALL(*mDataLoader, start(_)).Times(1);
+ EXPECT_CALL(*mDataLoader, destroy(_)).Times(2);
+ EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+ EXPECT_CALL(*mLooper, addFd(MockIncFs::kPendingReadsFd, _, _, _, _)).Times(1);
+ EXPECT_CALL(*mLooper, removeFd(MockIncFs::kPendingReadsFd)).Times(1);
+ TemporaryDir tempDir;
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
+ ASSERT_GE(storageId, 0);
+
+ ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+ .WillByDefault(Invoke(mDataLoaderManager,
+ &MockDataLoaderManager::bindToDataLoaderOkWithNoDelay));
+
+ ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+ {}, {}));
+
+ // Unavailable.
+ mDataLoaderManager->setDataLoaderStatusUnavailable();
+
+ // Timed callback present.
+ ASSERT_EQ(storageId, mTimedQueue->mId);
+ ASSERT_GE(mTimedQueue->mAfter, 10ms);
+ auto timedCallback = mTimedQueue->mWhat;
+ mTimedQueue->clearJob(storageId);
+
+ // Propagating unavailable and expecting it to trigger rebind with 1s retry delay.
+ ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+ .WillByDefault(Invoke(mDataLoaderManager,
+ &MockDataLoaderManager::bindToDataLoaderOkWith1sDelay));
+ timedCallback();
+
+ // Unavailable #2.
+ mDataLoaderManager->setDataLoaderStatusUnavailable();
+
+ // Timed callback present.
+ ASSERT_EQ(storageId, mTimedQueue->mId);
+ ASSERT_GE(mTimedQueue->mAfter, 10ms);
+ timedCallback = mTimedQueue->mWhat;
+ mTimedQueue->clearJob(storageId);
+
+ // Propagating unavailable and expecting it to trigger rebind with 10s retry delay.
+ // This time succeed.
+ mDataLoader->initializeCreateOk();
+ ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+ .WillByDefault(Invoke(mDataLoaderManager,
+ &MockDataLoaderManager::bindToDataLoaderOkWith10sDelay));
+ timedCallback();
+}
+
TEST_F(IncrementalServiceTest, testStartDataLoaderUnhealthyStorage) {
mIncFs->openMountSuccess();
@@ -1218,7 +1352,7 @@
ASSERT_NE(nullptr, mLooper->mCallbackData);
ASSERT_EQ(storageId, listener->mStorageId);
ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_OK, listener->mStatus);
- checkMillisSinceOldestPendingRead(storageId, 0);
+ checkHealthMetrics(storageId, 0, listener->mStatus);
// Looper/epoll callback.
mIncFs->waitForPendingReadsSuccess(kFirstTimestampUs);
@@ -1244,7 +1378,7 @@
ASSERT_EQ(nullptr, mLooper->mCallbackData);
ASSERT_EQ(storageId, listener->mStorageId);
ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_BLOCKED, listener->mStatus);
- checkMillisSinceOldestPendingRead(storageId, params.blockedTimeoutMs);
+ checkHealthMetrics(storageId, params.blockedTimeoutMs, listener->mStatus);
// Timed callback present.
ASSERT_EQ(storageId, mTimedQueue->mId);
@@ -1261,7 +1395,7 @@
ASSERT_EQ(nullptr, mLooper->mCallbackData);
ASSERT_EQ(storageId, listener->mStorageId);
ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_UNHEALTHY, listener->mStatus);
- checkMillisSinceOldestPendingRead(storageId, params.unhealthyTimeoutMs);
+ checkHealthMetrics(storageId, params.unhealthyTimeoutMs, listener->mStatus);
// Timed callback present.
ASSERT_EQ(storageId, mTimedQueue->mId);
@@ -1278,7 +1412,7 @@
ASSERT_EQ(nullptr, mLooper->mCallbackData);
ASSERT_EQ(storageId, listener->mStorageId);
ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_UNHEALTHY, listener->mStatus);
- checkMillisSinceOldestPendingRead(storageId, params.unhealthyTimeoutMs);
+ checkHealthMetrics(storageId, params.unhealthyTimeoutMs, listener->mStatus);
// Timed callback present.
ASSERT_EQ(storageId, mTimedQueue->mId);
@@ -1295,7 +1429,7 @@
ASSERT_NE(nullptr, mLooper->mCallbackData);
ASSERT_EQ(storageId, listener->mStorageId);
ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_OK, listener->mStatus);
- checkMillisSinceOldestPendingRead(storageId, 0);
+ checkHealthMetrics(storageId, 0, listener->mStatus);
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
@@ -2025,7 +2159,7 @@
ASSERT_TRUE(result.empty());
}
-TEST_F(IncrementalServiceTest, testNoMetrics) {
+TEST_F(IncrementalServiceTest, testNoDataLoaderMetrics) {
mVold->setIncFsMountOptionsSuccess();
TemporaryDir tempDir;
int storageId =
@@ -2040,7 +2174,12 @@
.c_str()),
&value));
ASSERT_EQ(expected, value);
- ASSERT_EQ(0, (int)result.size());
+ ASSERT_EQ(1, (int)result.size());
+ bool expectedReadLogsEnabled = false;
+ ASSERT_TRUE(
+ result.getBoolean(String16(BnIncrementalService::METRICS_READ_LOGS_ENABLED().c_str()),
+ &expectedReadLogsEnabled));
+ ASSERT_EQ(mVold->readLogsEnabled(), expectedReadLogsEnabled);
}
TEST_F(IncrementalServiceTest, testInvalidMetricsKeys) {
@@ -2057,7 +2196,7 @@
int64_t expected = -1, value = -1;
ASSERT_FALSE(result.getLong(String16("invalid"), &value));
ASSERT_EQ(expected, value);
- ASSERT_EQ(1, (int)result.size());
+ ASSERT_EQ(6, (int)result.size());
}
} // namespace android::os::incremental
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6dedca1..8dc5011 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -108,7 +108,6 @@
import com.android.server.audio.AudioService;
import com.android.server.biometrics.AuthService;
import com.android.server.biometrics.BiometricService;
-import com.android.server.biometrics.sensors.BiometricServiceCallback;
import com.android.server.biometrics.sensors.face.FaceService;
import com.android.server.biometrics.sensors.fingerprint.FingerprintService;
import com.android.server.biometrics.sensors.iris.IrisService;
@@ -214,11 +213,9 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
-import java.util.List;
import java.util.Locale;
import java.util.Timer;
import java.util.TreeSet;
@@ -2334,12 +2331,10 @@
final boolean hasFeatureFingerprint
= mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
- final List<BiometricServiceCallback> biometricServiceCallback = new ArrayList<>();
if (hasFeatureFace) {
t.traceBegin("StartFaceSensor");
final FaceService faceService =
mSystemServiceManager.startService(FaceService.class);
- biometricServiceCallback.add(faceService);
t.traceEnd();
}
@@ -2353,18 +2348,12 @@
t.traceBegin("StartFingerprintSensor");
final FingerprintService fingerprintService =
mSystemServiceManager.startService(FingerprintService.class);
- biometricServiceCallback.add(fingerprintService);
t.traceEnd();
}
// Start this service after all biometric sensor services are started.
t.traceBegin("StartBiometricService");
mSystemServiceManager.startService(BiometricService.class);
- for (BiometricServiceCallback service : biometricServiceCallback) {
- Slog.d(TAG, "Notifying onBiometricServiceReady for: "
- + service.getClass().getSimpleName());
- service.onBiometricServiceReady();
- }
t.traceEnd();
t.traceBegin("StartAuthService");
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 683fbd1..3bc1c8a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -51,6 +51,10 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_ALLOW_LIST;
+import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_COMPAT;
+import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_NOT_APPLICABLE;
+import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION;
import static com.android.server.alarm.AlarmManagerService.ACTIVE_INDEX;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.APP_STANDBY_BUCKET_CHANGED;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHARGING_STATUS_CHANGED;
@@ -359,6 +363,7 @@
.spyStatic(DeviceConfig.class)
.mockStatic(LocalServices.class)
.spyStatic(Looper.class)
+ .mockStatic(MetricsHelper.class)
.mockStatic(Settings.Global.class)
.mockStatic(ServiceManager.class)
.spyStatic(UserHandle.class)
@@ -418,6 +423,9 @@
spyOn(mService);
mService.onStart();
+ // Unable to mock mMockContext to return a mock stats manager.
+ // So just mocking the whole MetricsHelper instance.
+ mService.mMetricsHelper = mock(MetricsHelper.class);
spyOn(mService.mHandler);
// Stubbing the handler. Test should simulate any handling of messages synchronously.
doReturn(true).when(mService.mHandler).sendMessageAtTime(any(Message.class), anyLong());
@@ -492,7 +500,7 @@
IAlarmListener listener) {
mService.setImpl(type, triggerTime, windowLength, 0, null, listener, "test",
FLAG_STANDALONE | FLAG_PRIORITIZE, null, null, TEST_CALLING_UID,
- TEST_CALLING_PACKAGE, null);
+ TEST_CALLING_PACKAGE, null, 0);
}
private void setAllowWhileIdleAlarm(int type, long triggerTime, PendingIntent pi,
@@ -516,12 +524,12 @@
PendingIntent operation, long interval, int flags, int callingUid,
String callingPackage, Bundle idleOptions) {
mService.setImpl(type, triggerTime, windowLength, interval, operation, null, "test", flags,
- null, null, callingUid, callingPackage, idleOptions);
+ null, null, callingUid, callingPackage, idleOptions, 0);
}
private void setTestAlarmWithListener(int type, long triggerTime, IAlarmListener listener) {
mService.setImpl(type, triggerTime, WINDOW_EXACT, 0, null, listener, "test",
- FLAG_STANDALONE, null, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE, null);
+ FLAG_STANDALONE, null, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE, null, 0);
}
@@ -1898,7 +1906,8 @@
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(),
eq(FLAG_STANDALONE), isNull(), isNull(),
- eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull());
+ eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull(),
+ eq(EXACT_ALLOW_REASON_COMPAT));
}
@Test
@@ -1915,7 +1924,8 @@
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(),
eq(FLAG_ALLOW_WHILE_IDLE_COMPAT | FLAG_STANDALONE), isNull(), isNull(),
- eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
+ eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(),
+ eq(EXACT_ALLOW_REASON_COMPAT));
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
final int type = idleOptions.getTemporaryAppAllowlistType();
@@ -1935,7 +1945,8 @@
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), anyLong(), eq(0L),
eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(),
- isNull(), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
+ isNull(), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(),
+ eq(EXACT_ALLOW_REASON_NOT_APPLICABLE));
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
final int type = idleOptions.getTemporaryAppAllowlistType();
@@ -1955,7 +1966,8 @@
verify(mService).setImpl(eq(RTC_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(), eq(FLAG_STANDALONE | FLAG_WAKE_FROM_IDLE),
- isNull(), eq(alarmClock), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull());
+ isNull(), eq(alarmClock), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull(),
+ eq(EXACT_ALLOW_REASON_COMPAT));
}
@Test
@@ -1979,7 +1991,7 @@
verify(mService).setImpl(eq(RTC_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(), eq(FLAG_STANDALONE | FLAG_WAKE_FROM_IDLE),
isNull(), eq(alarmClock), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE),
- bundleCaptor.capture());
+ bundleCaptor.capture(), eq(EXACT_ALLOW_REASON_PERMISSION));
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
final int type = idleOptions.getTemporaryAppAllowlistType();
@@ -2042,7 +2054,8 @@
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(),
eq(FLAG_STANDALONE), isNull(), isNull(),
- eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
+ eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(),
+ eq(EXACT_ALLOW_REASON_PERMISSION));
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
final int type = idleOptions.getTemporaryAppAllowlistType();
@@ -2067,7 +2080,8 @@
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(),
eq(FLAG_STANDALONE), isNull(), isNull(),
- eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull());
+ eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull(),
+ eq(EXACT_ALLOW_REASON_ALLOW_LIST));
}
@Test
@@ -2087,7 +2101,8 @@
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(),
eq(FLAG_ALLOW_WHILE_IDLE | FLAG_STANDALONE), isNull(), isNull(),
- eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
+ eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(),
+ eq(EXACT_ALLOW_REASON_PERMISSION));
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
final int type = idleOptions.getTemporaryAppAllowlistType();
@@ -2113,7 +2128,8 @@
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(),
eq(FLAG_ALLOW_WHILE_IDLE_COMPAT | FLAG_STANDALONE), isNull(), isNull(),
- eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
+ eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(),
+ eq(EXACT_ALLOW_REASON_ALLOW_LIST));
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
final int type = idleOptions.getTemporaryAppAllowlistType();
@@ -2167,7 +2183,8 @@
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(4321L), anyLong(), eq(0L),
eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(),
- isNull(), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
+ isNull(), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(),
+ eq(EXACT_ALLOW_REASON_NOT_APPLICABLE));
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
final int type = idleOptions.getTemporaryAppAllowlistType();
@@ -2192,7 +2209,8 @@
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(),
eq(FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED | FLAG_STANDALONE), isNull(), isNull(),
- eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull());
+ eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull(),
+ eq(EXACT_ALLOW_REASON_ALLOW_LIST));
}
@Test
@@ -2492,6 +2510,28 @@
assertEquals(new ArraySet<>(appIds), mService.mExactAlarmCandidates);
}
+ @Test
+ public void alarmScheduledAtomPushed() {
+ for (int i = 0; i < 10; i++) {
+ final PendingIntent pi = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i, pi);
+
+ verify(() -> MetricsHelper.pushAlarmScheduled(argThat(a -> a.matches(pi, null))));
+ }
+ }
+
+ @Test
+ public void alarmBatchDeliveredAtomPushed() throws InterruptedException {
+ for (int i = 0; i < 10; i++) {
+ final int type = ((i & 1) == 0) ? ELAPSED_REALTIME : ELAPSED_REALTIME_WAKEUP;
+ setTestAlarm(type, mNowElapsedTest + i, getNewMockPendingIntent());
+ }
+ mNowElapsedTest += 100;
+ mTestTimer.expire();
+
+ verify(() -> MetricsHelper.pushAlarmBatchDelivered(10, 5));
+ }
+
@After
public void tearDown() {
if (mMockingSession != null) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
index 12894ae..ba0e555 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
@@ -18,7 +18,10 @@
import static android.app.AlarmManager.ELAPSED_REALTIME;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.RTC;
+import static android.app.AlarmManager.RTC_WAKEUP;
+import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_NOT_APPLICABLE;
import static com.android.server.alarm.Constants.TEST_CALLING_PACKAGE;
import static com.android.server.alarm.Constants.TEST_CALLING_UID;
@@ -33,6 +36,7 @@
import android.app.PendingIntent;
import android.platform.test.annotations.Presubmit;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -69,12 +73,13 @@
mock(PendingIntent.class));
return new Alarm(ELAPSED_REALTIME_WAKEUP, whenElapsed, whenElapsed, 0, 0,
mock(PendingIntent.class), null, null, null, 0, info, TEST_CALLING_UID,
- TEST_CALLING_PACKAGE, null);
+ TEST_CALLING_PACKAGE, null, EXACT_ALLOW_REASON_NOT_APPLICABLE);
}
private static Alarm createAlarm(int type, long whenElapsed, long windowLength, int flags) {
return new Alarm(type, whenElapsed, whenElapsed, windowLength, 0, mock(PendingIntent.class),
- null, null, null, flags, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE, null);
+ null, null, null, flags, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE, null,
+ EXACT_ALLOW_REASON_NOT_APPLICABLE);
}
private void addAlarmsToStore(Alarm... alarms) {
@@ -83,6 +88,11 @@
}
}
+ @Before
+ public void clear() {
+ mAlarmStore.remove(unused -> true);
+ }
+
@Test
public void add() {
final Alarm a1 = createAlarm(1, 0);
@@ -209,7 +219,6 @@
final Alarm a8 = createAlarm(8, 0);
final Alarm a10 = createAlarm(10, 0);
addAlarmsToStore(a8, a10, a5);
-
assertEquals(5, mAlarmStore.getNextDeliveryTime());
mAlarmStore.updateAlarmDeliveries(a -> {
@@ -241,4 +250,22 @@
mAlarmStore.remove(alarmClock::equals);
verify(onRemoved).run();
}
+
+ @Test
+ public void getCount() {
+ for (int i = 0; i < 10; i++) {
+ mAlarmStore.add(createAlarm(ELAPSED_REALTIME, i, 4, 0));
+ }
+ assertEquals(5, mAlarmStore.getCount(a -> a.getRequestedElapsed() < 5));
+ assertEquals(10, mAlarmStore.getCount(a -> a.windowLength == 4));
+
+ addAlarmsToStore(
+ createAlarm(RTC_WAKEUP, 45, 0, 53),
+ createAlarm(ELAPSED_REALTIME_WAKEUP, 60, 0, 53)
+ );
+
+ assertEquals(2, mAlarmStore.getCount(a -> a.wakeup));
+ assertEquals(2, mAlarmStore.getCount(a -> a.flags == 53));
+ assertEquals(0, mAlarmStore.getCount(a -> a.type == RTC));
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java
index b64528c..f11cba0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java
@@ -55,14 +55,14 @@
private Alarm createDefaultAlarm(long requestedElapsed, long windowLength, int flags) {
return new Alarm(ELAPSED_REALTIME, 0, requestedElapsed, windowLength, 0,
createAlarmSender(), null, null, null, flags, null, TEST_CALLING_UID,
- TEST_CALLING_PACKAGE, null);
+ TEST_CALLING_PACKAGE, null, 0);
}
private Alarm createAlarmClock(long requestedRtc) {
final AlarmManager.AlarmClockInfo info = mock(AlarmManager.AlarmClockInfo.class);
return new Alarm(RTC_WAKEUP, requestedRtc, requestedRtc, 0, 0, createAlarmSender(),
null, null, null, FLAG_WAKE_FROM_IDLE | FLAG_STANDALONE, info, TEST_CALLING_UID,
- TEST_CALLING_PACKAGE, null);
+ TEST_CALLING_PACKAGE, null, 0);
}
private PendingIntent createAlarmSender() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
index 0e795a9..403b4cd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
@@ -45,7 +45,7 @@
}
uidAlarms.add(new Alarm(
removeIt ? RTC : RTC_WAKEUP,
- 0, 0, 0, 0, null, null, null, null, 0, null, uid, name, null));
+ 0, 0, 0, 0, null, null, null, null, 0, null, uid, name, null, 0));
return all;
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerUtilsTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerUtilsTest.java
new file mode 100644
index 0000000..96103e3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerUtilsTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.am;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+@SmallTest
+public class ActivityManagerUtilsTest {
+ @Test
+ public void getAndroidIdHash() {
+ // getAndroidIdHash() essentially returns a random a value. Just make sure it's
+ // non-negative.
+ assertThat(ActivityManagerUtils.getAndroidIdHash()).isAtLeast(0);
+ }
+
+ @Test
+ public void getUnsignedHashCached() {
+ assertThat(ActivityManagerUtils.getUnsignedHashCached("x")).isEqualTo(
+ ActivityManagerUtils.getUnsignedHashCached("x"));
+
+ assertThat(ActivityManagerUtils.getUnsignedHashCached("x")).isNotEqualTo(
+ ActivityManagerUtils.getUnsignedHashCached("y"));
+ }
+
+ @Test
+ public void shouldSamplePackage_sampleNone() {
+ final int numTests = 100000;
+ for (int i = 0; i < numTests; i++) {
+ assertThat(ActivityManagerUtils.shouldSamplePackageForAtom("" + i, 0))
+ .isFalse();
+ }
+ }
+
+ @Test
+ public void shouldSamplePackage_sampleAll() {
+ final int numTests = 100000;
+
+ for (int i = 0; i < numTests; i++) {
+ assertThat(ActivityManagerUtils.shouldSamplePackageForAtom("" + i, 1))
+ .isTrue();
+ }
+ }
+
+ /**
+ * Make sure, with the same android ID, an expected rate of the packages are selected.
+ */
+ @Test
+ public void shouldSamplePackage_sampleSome_fixedAndroidId() {
+ checkShouldSamplePackage_fixedAndroidId(0.1f);
+ checkShouldSamplePackage_fixedAndroidId(0.5f);
+ checkShouldSamplePackage_fixedAndroidId(0.9f);
+ }
+
+ /**
+ * Make sure, the same package is selected on an expected rate of the devices.
+ */
+ @Test
+ public void shouldSamplePackage_sampleSome_fixedPackage() {
+ checkShouldSamplePackage_fixedPackage(0.1f);
+ checkShouldSamplePackage_fixedPackage(0.5f);
+ checkShouldSamplePackage_fixedPackage(0.9f);
+ }
+
+ private void checkShouldSamplePackage_fixedPackage(float sampleRate) {
+ checkShouldSamplePackage(sampleRate, sampleRate, true, false);
+ }
+
+ private void checkShouldSamplePackage_fixedAndroidId(float sampleRate) {
+ checkShouldSamplePackage(sampleRate, sampleRate, false, true);
+ }
+
+ @Test
+ public void testSheckShouldSamplePackage() {
+ // Just make sure checkShouldSamplePackage is actually working...
+ try {
+ checkShouldSamplePackage(0.3f, 0.6f, false, true);
+ fail();
+ } catch (AssertionError expected) {
+ }
+ try {
+ checkShouldSamplePackage(0.6f, 0.3f, true, false);
+ fail();
+ } catch (AssertionError expected) {
+ }
+ }
+
+ private void checkShouldSamplePackage(float inputSampleRate, float expectedRate,
+ boolean fixedPackage, boolean fixedAndroidId) {
+ final int numTests = 100000;
+
+ try {
+ int numSampled = 0;
+ for (int i = 0; i < numTests; i++) {
+ final String pkg = fixedPackage ? "fixed-package" : "" + i;
+ ActivityManagerUtils.injectAndroidIdForTest(
+ fixedAndroidId ? "fixed-android-id" : "" + i);
+
+ if (ActivityManagerUtils.shouldSamplePackageForAtom(pkg, inputSampleRate)) {
+ numSampled++;
+ }
+ assertThat(ActivityManagerUtils.getUnsignedHashCached(pkg)).isEqualTo(
+ ActivityManagerUtils.getUnsignedHashCached(pkg));
+ }
+ final double actualSampleRate = ((double) numSampled) / numTests;
+
+ assertThat(actualSampleRate).isWithin(0.05).of(expectedRate);
+ } finally {
+ ActivityManagerUtils.injectAndroidIdForTest(null);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index 10a7a50..6f0c8e1 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -31,11 +31,14 @@
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.PromptInfo;
+import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceService;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.iris.IIrisService;
import android.os.Binder;
@@ -45,11 +48,17 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import com.android.internal.R;
+
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
@Presubmit
@SmallTest
public class AuthServiceTest {
@@ -62,6 +71,8 @@
@Mock
private Context mContext;
@Mock
+ private Resources mResources;
+ @Mock
private PackageManager mPackageManager;
@Mock
IBiometricServiceReceiver mReceiver;
@@ -77,6 +88,10 @@
IFaceService mFaceService;
@Mock
AppOpsManager mAppOpsManager;
+ @Captor
+ private ArgumentCaptor<List<FingerprintSensorPropertiesInternal>> mFingerprintPropsCaptor;
+ @Captor
+ private ArgumentCaptor<List<FaceSensorPropertiesInternal>> mFacePropsCaptor;
@Before
public void setUp() {
@@ -89,7 +104,16 @@
"2:8:15", // ID2:Face:Strong
};
+ when(mResources.getIntArray(eq(R.array.config_udfps_sensor_props))).thenReturn(new int[0]);
+ when(mResources.getBoolean(eq(R.bool.config_is_powerbutton_fps))).thenReturn(false);
+ when(mResources.getInteger(eq(R.integer.config_fingerprintMaxTemplatesPerUser))).thenReturn(
+ 1);
+ when(mResources.getBoolean(eq(R.bool.config_faceAuthSupportsSelfIllumination))).thenReturn(
+ false);
+ when(mResources.getInteger(eq(R.integer.config_faceMaxTemplatesPerUser))).thenReturn(1);
+
when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mContext.getResources()).thenReturn(mResources);
when(mInjector.getBiometricService()).thenReturn(mBiometricService);
when(mInjector.getConfiguration(any())).thenReturn(config);
when(mInjector.getFingerprintService()).thenReturn(mFingerprintService);
@@ -119,11 +143,18 @@
}
@Test
- public void testRegisterAuthenticator_initializesConfiguration() throws Exception {
+ public void testRegisterAuthenticator_registerAuthenticators() throws Exception {
+ final int fingerprintId = 0;
+ final int fingerprintStrength = 15;
+
+ final int faceId = 1;
+ final int faceStrength = 4095;
final String[] config = {
- "0:2:15", // ID0:Fingerprint:Strong
- "1:8:4095", // ID2:Face:Convenience
+ // ID0:Fingerprint:Strong
+ String.format("%d:2:%d", fingerprintId, fingerprintStrength),
+ // ID2:Face:Convenience
+ String.format("%d:8:%d", faceId, faceStrength)
};
when(mInjector.getConfiguration(any())).thenReturn(config);
@@ -131,15 +162,18 @@
mAuthService = new AuthService(mContext, mInjector);
mAuthService.onStart();
- final int fingerprintId = 0;
- final int faceId = 1;
+ verify(mFingerprintService).registerAuthenticators(mFingerprintPropsCaptor.capture());
+ final FingerprintSensorPropertiesInternal fingerprintProp =
+ mFingerprintPropsCaptor.getValue().get(0);
+ assertEquals(fingerprintProp.sensorId, fingerprintId);
+ assertEquals(fingerprintProp.sensorStrength,
+ Utils.authenticatorStrengthToPropertyStrength(fingerprintStrength));
- final int fingerprintStrength = 15;
- final int faceStrength = 4095;
-
- verify(mFingerprintService).initializeConfiguration(eq(fingerprintId),
- eq(fingerprintStrength));
- verify(mFaceService).initializeConfiguration(eq(faceId), eq(faceStrength));
+ verify(mFaceService).registerAuthenticators(mFacePropsCaptor.capture());
+ final FaceSensorPropertiesInternal faceProp = mFacePropsCaptor.getValue().get(0);
+ assertEquals(faceProp.sensorId, faceId);
+ assertEquals(faceProp.sensorStrength,
+ Utils.authenticatorStrengthToPropertyStrength(faceStrength));
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index c5ed20a..4d1f241 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -37,6 +37,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.testing.TestableContext;
import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
@@ -47,6 +48,7 @@
import com.android.server.biometrics.sensors.BiometricScheduler.Operation;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -63,10 +65,12 @@
private IBinder mToken;
@Mock
- private Context mContext;
- @Mock
private IBiometricService mBiometricService;
+ @Rule
+ public final TestableContext mContext =
+ new TestableContext(InstrumentationRegistry.getContext(), null);
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
index 392535e..0b59be6 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
@@ -22,7 +22,10 @@
import static org.mockito.Mockito.when;
import android.content.Context;
-import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.ComponentInfoInternal;
+import android.hardware.biometrics.SensorProperties;
+import android.hardware.face.FaceSensorProperties;
+import android.hardware.face.FaceSensorPropertiesInternal;
import android.os.Binder;
import android.os.IBinder;
import android.os.UserManager;
@@ -40,6 +43,7 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.List;
@Presubmit
@SmallTest
@@ -71,9 +75,18 @@
when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>());
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
- mFace10 = new Face10(mContext, SENSOR_ID, BiometricManager.Authenticators.BIOMETRIC_STRONG,
- mLockoutResetDispatcher, false /* supportsSelfIllumination */,
- 1 /* maxTemplatesAllowed */, mScheduler);
+
+ final int maxEnrollmentsPerUser = 1;
+ final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+ final boolean supportsFaceDetection = false;
+ final boolean supportsSelfIllumination = false;
+ final boolean resetLockoutRequiresChallenge = false;
+ final FaceSensorPropertiesInternal sensorProps = new FaceSensorPropertiesInternal(SENSOR_ID,
+ SensorProperties.STRENGTH_STRONG, maxEnrollmentsPerUser, componentInfo,
+ FaceSensorProperties.TYPE_UNKNOWN, supportsFaceDetection, supportsSelfIllumination,
+ resetLockoutRequiresChallenge);
+
+ mFace10 = new Face10(mContext, sensorProps, mLockoutResetDispatcher, mScheduler);
mBinder = new Binder();
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
index 904ade8..0a0dcc9 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
@@ -25,8 +25,10 @@
import android.content.Context;
import android.content.res.Resources;
-import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Handler;
import android.os.Looper;
import android.os.UserManager;
@@ -46,6 +48,7 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.List;
@Presubmit
@SmallTest
@@ -83,10 +86,18 @@
.thenReturn(5);
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
- mFingerprint21 = new TestableFingerprint21(mContext, mScheduler,
- new Handler(Looper.getMainLooper()), SENSOR_ID,
- BiometricManager.Authenticators.BIOMETRIC_WEAK, mLockoutResetDispatcher,
- mHalResultController);
+
+ final int maxEnrollmentsPerUser = 1;
+ final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+ final boolean resetLockoutRequiresHardwareAuthToken = false;
+ final FingerprintSensorPropertiesInternal sensorProps =
+ new FingerprintSensorPropertiesInternal(SENSOR_ID,
+ FingerprintSensorProperties.STRENGTH_WEAK, maxEnrollmentsPerUser,
+ componentInfo, FingerprintSensorProperties.TYPE_UNKNOWN,
+ resetLockoutRequiresHardwareAuthToken);
+
+ mFingerprint21 = new TestableFingerprint21(mContext, sensorProps, mScheduler,
+ new Handler(Looper.getMainLooper()), mLockoutResetDispatcher, mHalResultController);
}
@Test
@@ -107,12 +118,11 @@
private static class TestableFingerprint21 extends Fingerprint21 {
TestableFingerprint21(@NonNull Context context,
- @NonNull BiometricScheduler scheduler,
- @NonNull Handler handler, int sensorId, int strength,
+ @NonNull FingerprintSensorPropertiesInternal sensorProps,
+ @NonNull BiometricScheduler scheduler, @NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull HalResultController controller) {
- super(context, scheduler, handler, sensorId, strength, lockoutResetDispatcher,
- controller);
+ super(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 7cd6028..f156779 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -93,9 +93,10 @@
private static final long SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS = 10;
private static final String VIRTUAL_DISPLAY_NAME = "Test Virtual Display";
private static final String PACKAGE_NAME = "com.android.frameworks.servicestests";
- private static final long ALL_DISPLAY_EVENTS = DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+ private static final long STANDARD_DISPLAY_EVENTS = DisplayManager.EVENT_FLAG_DISPLAY_ADDED
| DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
+
@Rule
public TestRule compatChangeRule = new PlatformCompatChangeRule();
@@ -764,7 +765,8 @@
// register display listener callback
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
- displayManagerBinderService.registerCallbackWithEventMask(callback, ALL_DISPLAY_EVENTS);
+ displayManagerBinderService.registerCallbackWithEventMask(
+ callback, STANDARD_DISPLAY_EVENTS);
waitForIdleHandler(handler);
@@ -793,7 +795,7 @@
// register display listener callback
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
- long allEventsExceptDisplayAdded = ALL_DISPLAY_EVENTS
+ long allEventsExceptDisplayAdded = STANDARD_DISPLAY_EVENTS
& ~DisplayManager.EVENT_FLAG_DISPLAY_ADDED;
displayManagerBinderService.registerCallbackWithEventMask(callback,
allEventsExceptDisplayAdded);
@@ -862,7 +864,7 @@
waitForIdleHandler(handler);
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
- long allEventsExceptDisplayRemoved = ALL_DISPLAY_EVENTS
+ long allEventsExceptDisplayRemoved = STANDARD_DISPLAY_EVENTS
& ~DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
displayManagerBinderService.registerCallbackWithEventMask(callback,
allEventsExceptDisplayRemoved);
@@ -1032,7 +1034,8 @@
// register display listener callback
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(displayId);
- displayManagerBinderService.registerCallbackWithEventMask(callback, ALL_DISPLAY_EVENTS);
+ displayManagerBinderService.registerCallbackWithEventMask(
+ callback, STANDARD_DISPLAY_EVENTS);
return callback;
}
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
new file mode 100644
index 0000000..88a21b4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
+import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
+import com.android.server.testutils.OffsettableClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class HighBrightnessModeControllerTest {
+
+ private static final int MINIMUM_LUX = 100;
+ private static final float TRANSITION_POINT = 0.763f;
+ private static final long TIME_WINDOW_MILLIS = 55 * 1000;
+ private static final long TIME_ALLOWED_IN_WINDOW_MILLIS = 12 * 1000;
+ private static final long TIME_MINIMUM_AVAILABLE_TO_ENABLE_MILLIS = 5 * 1000;
+
+ private static final float DEFAULT_MIN = 0.01f;
+ private static final float DEFAULT_MAX = 0.80f;
+
+ private static final float EPSILON = 0.000001f;
+
+ private OffsettableClock mClock;
+ private TestLooper mTestLooper;
+ private Handler mHandler;
+
+ private static final HighBrightnessModeData DEFAULT_HBM_DATA =
+ new HighBrightnessModeData(MINIMUM_LUX, TRANSITION_POINT, TIME_WINDOW_MILLIS,
+ TIME_ALLOWED_IN_WINDOW_MILLIS, TIME_MINIMUM_AVAILABLE_TO_ENABLE_MILLIS);
+
+ @Before
+ public void setUp() {
+ mClock = new OffsettableClock.Stopped();
+ mTestLooper = new TestLooper(mClock::now);
+ mHandler = new Handler(mTestLooper.getLooper(), new Handler.Callback() {
+ @Override
+ public boolean handleMessage(Message msg) {
+ return true;
+ }
+ });
+ }
+
+ /////////////////
+ // Test Methods
+ /////////////////
+
+ @Test
+ public void testNoHbmData() {
+ final HighBrightnessModeController hbmc = new HighBrightnessModeController(
+ mClock::now, mHandler, DEFAULT_MIN, DEFAULT_MAX, null, () -> {});
+ assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
+ }
+
+ @Test
+ public void testNoHbmData_Enabled() {
+ final HighBrightnessModeController hbmc = new HighBrightnessModeController(
+ mClock::now, mHandler, DEFAULT_MIN, DEFAULT_MAX, null, () -> {});
+ hbmc.setAutoBrightnessEnabled(true);
+ hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range
+ assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
+ }
+
+ @Test
+ public void testOffByDefault() {
+ final HighBrightnessModeController hbmc = createDefaultHbm();
+
+ assertState(hbmc, DEFAULT_MIN, TRANSITION_POINT, HIGH_BRIGHTNESS_MODE_OFF);
+ }
+
+ @Test
+ public void testAutoBrightnessEnabled_NoLux() {
+ final HighBrightnessModeController hbmc = createDefaultHbm();
+
+ hbmc.setAutoBrightnessEnabled(true);
+ assertState(hbmc, DEFAULT_MIN, TRANSITION_POINT, HIGH_BRIGHTNESS_MODE_OFF);
+ }
+
+ @Test
+ public void testAutoBrightnessEnabled_LowLux() {
+ final HighBrightnessModeController hbmc = createDefaultHbm();
+
+ hbmc.setAutoBrightnessEnabled(true);
+ hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range
+ assertState(hbmc, DEFAULT_MIN, TRANSITION_POINT, HIGH_BRIGHTNESS_MODE_OFF);
+ }
+
+ @Test
+ public void testAutoBrightnessEnabled_HighLux() {
+ final HighBrightnessModeController hbmc = createDefaultHbm();
+
+ hbmc.setAutoBrightnessEnabled(true);
+ hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
+ assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
+ }
+
+ @Test
+ public void testAutoBrightnessEnabled_HighLux_ThenDisable() {
+ final HighBrightnessModeController hbmc = createDefaultHbm();
+
+ hbmc.setAutoBrightnessEnabled(true);
+ hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
+ hbmc.setAutoBrightnessEnabled(false);
+
+ assertState(hbmc, DEFAULT_MIN, TRANSITION_POINT, HIGH_BRIGHTNESS_MODE_OFF);
+ }
+
+ @Test
+ public void testWithinHighRange_thenOverTime_thenEarnBackTime() {
+ final HighBrightnessModeController hbmc = createDefaultHbm();
+
+ hbmc.setAutoBrightnessEnabled(true);
+ hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
+ hbmc.onAutoBrightnessChanged(TRANSITION_POINT + 0.01f);
+
+ // Verify we are in HBM
+ assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
+
+ // Use up all the time in the window.
+ advanceTime(TIME_ALLOWED_IN_WINDOW_MILLIS);
+
+ // Verify we are not out of HBM
+ assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
+
+ // Shift time so that the HBM event is at the beginning of the current window
+ advanceTime(TIME_WINDOW_MILLIS - TIME_ALLOWED_IN_WINDOW_MILLIS);
+ // Shift time again so that we are just below the minimum allowable
+ advanceTime(TIME_MINIMUM_AVAILABLE_TO_ENABLE_MILLIS - 1);
+
+ // Verify we are not out of HBM
+ assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
+
+ // Advance the necessary millisecond
+ advanceTime(1);
+
+ // Verify we are allowed HBM again.
+ assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
+ }
+
+ @Test
+ public void testInHBM_ThenLowLux() {
+ final HighBrightnessModeController hbmc = createDefaultHbm();
+
+ hbmc.setAutoBrightnessEnabled(true);
+ hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
+ hbmc.onAutoBrightnessChanged(TRANSITION_POINT + 0.01f);
+
+ // Verify we are in HBM
+ assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
+
+ advanceTime(TIME_ALLOWED_IN_WINDOW_MILLIS / 2);
+
+ // Verify we are in HBM
+ assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
+
+ hbmc.onAmbientLuxChange(1);
+ advanceTime(TIME_ALLOWED_IN_WINDOW_MILLIS / 2 + 1);
+
+ // Verify we are out of HBM
+ assertState(hbmc, DEFAULT_MIN, TRANSITION_POINT, HIGH_BRIGHTNESS_MODE_OFF);
+
+ }
+
+ @Test
+ public void testInHBM_TestMultipleEvents_DueToAutoBrightness() {
+ final HighBrightnessModeController hbmc = createDefaultHbm();
+
+ hbmc.setAutoBrightnessEnabled(true);
+ hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
+
+ hbmc.onAutoBrightnessChanged(TRANSITION_POINT + 0.01f);
+ advanceTime(TIME_ALLOWED_IN_WINDOW_MILLIS / 2);
+
+ // Verify we are in HBM
+ assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
+
+ hbmc.onAutoBrightnessChanged(TRANSITION_POINT - 0.01f);
+ advanceTime(1);
+
+ assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
+
+ hbmc.onAutoBrightnessChanged(TRANSITION_POINT + 0.01f);
+ advanceTime(TIME_ALLOWED_IN_WINDOW_MILLIS / 2);
+
+ assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
+
+ advanceTime(2);
+
+ // Now we should be out again.
+ assertState(hbmc, DEFAULT_MIN, TRANSITION_POINT, HIGH_BRIGHTNESS_MODE_OFF);
+ }
+
+ @Test
+ public void testInHBM_TestMultipleEvents_DueToLux() {
+ final HighBrightnessModeController hbmc = createDefaultHbm();
+
+ hbmc.setAutoBrightnessEnabled(true);
+ hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
+
+ // Go into HBM for half the allowed window
+ hbmc.onAutoBrightnessChanged(TRANSITION_POINT + 0.01f);
+ advanceTime(TIME_ALLOWED_IN_WINDOW_MILLIS / 2);
+ assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
+
+ // Move lux below threshold (ending first event);
+ hbmc.onAmbientLuxChange(MINIMUM_LUX - 1);
+ hbmc.onAutoBrightnessChanged(TRANSITION_POINT);
+ assertState(hbmc, DEFAULT_MIN, TRANSITION_POINT, HIGH_BRIGHTNESS_MODE_OFF);
+
+ // Move up some amount of time so that there's still time in the window even after a
+ // second event.
+ advanceTime((TIME_WINDOW_MILLIS - TIME_ALLOWED_IN_WINDOW_MILLIS) / 2);
+ assertState(hbmc, DEFAULT_MIN, TRANSITION_POINT, HIGH_BRIGHTNESS_MODE_OFF);
+
+ // Go into HBM for just under the second half of allowed window
+ hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
+ hbmc.onAutoBrightnessChanged(TRANSITION_POINT + 1);
+ advanceTime((TIME_ALLOWED_IN_WINDOW_MILLIS / 2) - 1);
+
+ assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
+
+ // Now exhaust the time
+ advanceTime(2);
+ assertState(hbmc, DEFAULT_MIN, TRANSITION_POINT, HIGH_BRIGHTNESS_MODE_OFF);
+ }
+
+ private void assertState(HighBrightnessModeController hbmc,
+ float brightnessMin, float brightnessMax, int hbmMode) {
+ assertEquals(brightnessMin, hbmc.getCurrentBrightnessMin(), EPSILON);
+ assertEquals(brightnessMax, hbmc.getCurrentBrightnessMax(), EPSILON);
+ assertEquals(hbmMode, hbmc.getHighBrightnessMode());
+ }
+
+ // Creates instance with standard initialization values.
+ private HighBrightnessModeController createDefaultHbm() {
+ return new HighBrightnessModeController(mClock::now, mHandler, DEFAULT_MIN, DEFAULT_MAX,
+ DEFAULT_HBM_DATA, () -> {});
+ }
+
+ private void advanceTime(long timeMs) {
+ mClock.fastForward(timeMs);
+ mTestLooper.dispatchAll();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
index d784a22..8279624 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -27,17 +27,20 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.PropertyInvalidatedCache;
import android.content.Context;
+import android.content.res.Resources;
+import android.os.Handler;
import android.os.Parcel;
import android.os.Process;
+import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
import android.view.DisplayAddress;
import android.view.DisplayInfo;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -61,9 +64,12 @@
private DisplayDeviceRepository mDisplayDeviceRepo;
private LogicalDisplayMapper mLogicalDisplayMapper;
- private Context mContext;
+ private TestLooper mLooper;
+ private Handler mHandler;
@Mock LogicalDisplayMapper.Listener mListenerMock;
+ @Mock Context mContextMock;
+ @Mock Resources mResourcesMock;
@Captor ArgumentCaptor<LogicalDisplay> mDisplayCaptor;
@@ -73,7 +79,6 @@
System.setProperty("dexmaker.share_classloader", "true");
MockitoAnnotations.initMocks(this);
- mContext = InstrumentationRegistry.getContext();
mDisplayDeviceRepo = new DisplayDeviceRepository(
new DisplayManagerService.SyncRoot(),
new PersistentDataStore(new PersistentDataStore.Injector() {
@@ -94,7 +99,15 @@
// Disable binder caches in this process.
PropertyInvalidatedCache.disableForTestMode();
- mLogicalDisplayMapper = new LogicalDisplayMapper(mDisplayDeviceRepo, mListenerMock);
+ when(mContextMock.getResources()).thenReturn(mResourcesMock);
+ when(mResourcesMock.getBoolean(
+ com.android.internal.R.bool.config_supportsConcurrentInternalDisplays))
+ .thenReturn(true);
+
+ mLooper = new TestLooper();
+ mHandler = new Handler(mLooper.getLooper());
+ mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mDisplayDeviceRepo,
+ mListenerMock, new DisplayManagerService.SyncRoot(), mHandler);
}
@@ -299,7 +312,7 @@
private DisplayDeviceInfo mSentInfo;
TestDisplayDevice() {
- super(null, null, "test_display_" + sUniqueTestDisplayId++, mContext);
+ super(null, null, "test_display_" + sUniqueTestDisplayId++, mContextMock);
mInfo = new DisplayDeviceInfo();
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
index ef7b274..011b8f8 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
@@ -138,6 +138,7 @@
mDevicePowerStatusAction = DevicePowerStatusAction.create(mPlaybackDevice, ADDR_TV,
mCallbackMock);
mTestLooper.dispatchAll();
+ mNativeWrapper.clearResultMessages();
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 80da696..a29a76b 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -60,6 +60,7 @@
@RunWith(JUnit4.class)
/** Tests for {@link HdmiCecLocalDevicePlayback} class. */
public class HdmiCecLocalDevicePlaybackTest {
+ private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1;
private static final int PORT_1 = 1;
private static final HdmiDeviceInfo INFO_TV = new HdmiDeviceInfo(
@@ -1045,6 +1046,10 @@
assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
// 4. DUT turned off.
mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
+ // TODO(b/184939731): remove waiting times once pending actions no longer block <Standby>
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
mTestLooper.dispatchAll();
HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
@@ -1502,6 +1507,7 @@
@Test
public void queryDisplayStatus() {
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
mHdmiControlService.queryDisplayStatus(new IHdmiControlCallback.Stub() {
@Override
public void onComplete(int result) {
@@ -1618,6 +1624,12 @@
@Test
public void shouldHandleTvPowerKey_CecDisabled() {
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ HdmiCecMessage reportPowerStatusMessage = HdmiCecMessageBuilder.buildReportPowerStatus(
+ Constants.ADDR_TV, mPlaybackLogicalAddress, HdmiControlManager.POWER_STATUS_ON);
+ mNativeWrapper.onCecMessage(reportPowerStatusMessage);
+ mTestLooper.dispatchAll();
+
mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
@@ -1626,6 +1638,12 @@
@Test
public void shouldHandleTvPowerKey_PowerControlModeNone() {
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ HdmiCecMessage reportPowerStatusMessage = HdmiCecMessageBuilder.buildReportPowerStatus(
+ Constants.ADDR_TV, mPlaybackLogicalAddress, HdmiControlManager.POWER_STATUS_ON);
+ mNativeWrapper.onCecMessage(reportPowerStatusMessage);
+ mTestLooper.dispatchAll();
+
mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
HdmiControlManager.POWER_CONTROL_MODE_NONE);
@@ -1633,7 +1651,22 @@
}
@Test
+ public void shouldHandleTvPowerKey_CecNotAvailable() {
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ // TV doesn't report its power status
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mHdmiControlService.shouldHandleTvPowerKey()).isFalse();
+ }
+
+ @Test
public void shouldHandleTvPowerKey_CecEnabled_PowerControlModeTv() {
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ HdmiCecMessage reportPowerStatusMessage = HdmiCecMessageBuilder.buildReportPowerStatus(
+ Constants.ADDR_TV, mPlaybackLogicalAddress, HdmiControlManager.POWER_STATUS_ON);
+ mNativeWrapper.onCecMessage(reportPowerStatusMessage);
+ mTestLooper.dispatchAll();
+
mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 950b8a2..c7a508a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -61,6 +61,7 @@
@RunWith(JUnit4.class)
/** Tests for {@link HdmiCecLocalDeviceTv} class. */
public class HdmiCecLocalDeviceTvTest {
+ private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1;
private HdmiControlService mHdmiControlService;
private HdmiCecController mHdmiCecController;
@@ -294,6 +295,10 @@
HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED);
mTestLooper.dispatchAll();
mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
+ // TODO(184939731): remove waiting times once pending actions no longer block <Standby>
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
mTestLooper.dispatchAll();
HdmiCecMessage standby = HdmiCecMessageBuilder.buildStandby(ADDR_TV, ADDR_BROADCAST);
assertThat(mNativeWrapper.getResultMessages()).contains(standby);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
index 5b01920..2307a85fe 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
@@ -392,9 +392,9 @@
@Test
public void isValid_giveFeatures() {
assertMessageValidity("40:A5").isEqualTo(OK);
+ assertMessageValidity("F0:A5").isEqualTo(OK);
assertMessageValidity("4F:A5").isEqualTo(ERROR_DESTINATION);
- assertMessageValidity("F0:A5").isEqualTo(ERROR_SOURCE);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
index d74bff2..4893173 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
@@ -142,6 +142,7 @@
mPhysicalAddress = 0x2000;
mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
mTestLooper.dispatchAll();
+ mNativeWrapper.clearResultMessages();
}
private OneTouchPlayAction createOneTouchPlayAction(HdmiCecLocalDevicePlayback device,
@@ -161,6 +162,7 @@
mLocalDevices.add(playbackDevice);
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
+ mNativeWrapper.clearResultMessages();
TestActionTimer actionTimer = new TestActionTimer();
TestCallback callback = new TestCallback();
@@ -203,6 +205,7 @@
mLocalDevices.add(playbackDevice);
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
+ mNativeWrapper.clearResultMessages();
TestActionTimer actionTimer = new TestActionTimer();
TestCallback callback = new TestCallback();
@@ -245,6 +248,7 @@
mLocalDevices.add(playbackDevice);
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
+ mNativeWrapper.clearResultMessages();
TestActionTimer actionTimer = new TestActionTimer();
TestCallback callback = new TestCallback();
@@ -297,6 +301,7 @@
mLocalDevices.add(playbackDevice);
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
+ mNativeWrapper.clearResultMessages();
TestActionTimer actionTimer = new TestActionTimer();
TestCallback callback = new TestCallback();
@@ -342,6 +347,7 @@
mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_TV,
HdmiControlManager.POWER_STATUS_ON);
mTestLooper.dispatchAll();
+ mNativeWrapper.clearResultMessages();
TestActionTimer actionTimer = new TestActionTimer();
TestCallback callback = new TestCallback();
@@ -376,6 +382,7 @@
mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_TV,
HdmiControlManager.POWER_STATUS_UNKNOWN);
mTestLooper.dispatchAll();
+ mNativeWrapper.clearResultMessages();
TestActionTimer actionTimer = new TestActionTimer();
TestCallback callback = new TestCallback();
@@ -420,6 +427,7 @@
mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_TV,
HdmiControlManager.POWER_STATUS_STANDBY);
mTestLooper.dispatchAll();
+ mNativeWrapper.clearResultMessages();
TestActionTimer actionTimer = new TestActionTimer();
TestCallback callback = new TestCallback();
diff --git a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
index f0a9a008..75aacd1 100644
--- a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
@@ -47,6 +47,9 @@
@SmallTest
public class LightsServiceTest {
+ private static final int HIGH_PRIORITY = Integer.MAX_VALUE;
+ private static final int DEFAULT_PRIORITY = 0;
+
private final ILights mHal = new ILights.Stub() {
@Override
public void setLightState(int id, HwLightState state) {
@@ -188,4 +191,30 @@
// Then the light should turn back off.
assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0);
}
+
+ @Test
+ public void testControlLights_higherPriorityCallerWinsContention() throws Exception {
+ LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper());
+ LightsManager manager = new SystemLightsManager(mContext, service.mManagerService);
+ Light micLight = manager.getLights().get(0);
+
+ // The light should begin by being off.
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(TRANSPARENT);
+
+ try (LightsManager.LightsSession session1 = manager.openSession(DEFAULT_PRIORITY)) {
+ try (LightsManager.LightsSession session2 = manager.openSession(HIGH_PRIORITY)) {
+ // When session1 and session2 both request the same light:
+ session1.requestLights(
+ new Builder().addLight(micLight, new LightState(BLUE)).build());
+ session2.requestLights(
+ new Builder().addLight(micLight, new LightState(WHITE)).build());
+ // Then session2 should win because it has a higher priority.
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(WHITE);
+ }
+ // Then session1 should have its request go into effect.
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(BLUE);
+ }
+ // Then the light should turn off because there are no more sessions.
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(TRANSPARENT);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 5d60a89..807ead3 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -155,7 +155,8 @@
}
@Override
- public ManagedProfilePasswordCache getManagedProfilePasswordCache() {
+ public ManagedProfilePasswordCache getManagedProfilePasswordCache(
+ java.security.KeyStore ks) {
return mock(ManagedProfilePasswordCache.class);
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
index 8c92a47..0e615a6 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
@@ -51,8 +51,6 @@
private InputSensorInfo mMockInputSensorInfo;
@Mock
private SensorManager mMockSensorManager;
- @Mock
- private WindowManagerService mMockWindowManagerService;
private TestableRotationResolver mFakeRotationResolverInternal;
private com.android.server.wm.WindowOrientationListener mWindowOrientationListener;
@@ -69,7 +67,7 @@
mFakeRotationResolverInternal = new TestableRotationResolver();
doReturn(mMockSensorManager).when(mMockContext).getSystemService(Context.SENSOR_SERVICE);
mWindowOrientationListener = new TestableWindowOrientationListener(mMockContext,
- mMockHandler, mMockWindowManagerService);
+ mMockHandler);
mWindowOrientationListener.mRotationResolverService = mFakeRotationResolverInternal;
mFakeSensor = new Sensor(mMockInputSensorInfo);
@@ -115,9 +113,8 @@
final class TestableWindowOrientationListener extends WindowOrientationListener {
- TestableWindowOrientationListener(Context context, Handler handler,
- WindowManagerService service) {
- super(context, handler, service);
+ TestableWindowOrientationListener(Context context, Handler handler) {
+ super(context, handler);
this.mOrientationJudge = new OrientationSensorJudge();
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
index a2ad89e..a05fea2 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
@@ -144,15 +144,21 @@
@Test
public void testRemoveChannelNotifications() {
List<String> expected = new ArrayList<>();
- for (int i = 0; i < SIZE; i++) {
+ // Add one extra notification to the beginning to test when 2 adjacent notifications will be
+ // removed in the same pass.
+ StatusBarNotification sbn0 = getNotification("pkg", 0, UserHandle.of(USER_CURRENT));
+ mArchive.record(sbn0, REASON_CANCEL);
+ for (int i = 0; i < SIZE - 1; i++) {
StatusBarNotification sbn = getNotification("pkg", i, UserHandle.of(USER_CURRENT));
mArchive.record(sbn, REASON_CANCEL);
- if (i != 3) {
- // Will delete notification for this user in channel "test3".
+ if (i != 0 && i != SIZE - 2) {
+ // Will delete notification for this user in channel "test0", and also the last
+ // element in the list.
expected.add(sbn.getKey());
}
}
- mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test3");
+ mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test0");
+ mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test" + (SIZE - 2));
List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
assertThat(actual).hasSize(expected.size());
for (StatusBarNotification sbn : actual) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
index 9433bf2..6a8f602 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
@@ -22,12 +22,15 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Person;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -72,6 +75,7 @@
private NotificationRecord mRecordMinCallNonInterruptive;
private NotificationRecord mRecordMinCall;
private NotificationRecord mRecordHighCall;
+ private NotificationRecord mRecordHighCallStyle;
private NotificationRecord mRecordEmail;
private NotificationRecord mRecordInlineReply;
private NotificationRecord mRecordSms;
@@ -90,9 +94,12 @@
int userId = UserHandle.myUserId();
when(mContext.getResources()).thenReturn(getContext().getResources());
+ when(mContext.getTheme()).thenReturn(getContext().getTheme());
when(mContext.getContentResolver()).thenReturn(getContext().getContentResolver());
when(mContext.getPackageManager()).thenReturn(mPm);
when(mContext.getSystemService(eq(Context.TELECOM_SERVICE))).thenReturn(mTm);
+ when(mContext.getString(anyInt())).thenCallRealMethod();
+ when(mContext.getColor(anyInt())).thenCallRealMethod();
when(mTm.getDefaultDialerPackage()).thenReturn(callPkg);
final ApplicationInfo legacy = new ApplicationInfo();
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
@@ -137,6 +144,19 @@
new UserHandle(userId), "", 1999), getDefaultChannel());
mRecordHighCall.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
+ Notification nHighCallStyle = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+ .setStyle(Notification.CallStyle.forOngoingCall(
+ new Person.Builder().setName("caller").build(),
+ mock(PendingIntent.class)
+ ))
+ .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+ .build();
+ mRecordHighCallStyle = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
+ callPkg, 1, "highCallStyle", callUid, callUid, nHighCallStyle,
+ new UserHandle(userId), "", 2000), getDefaultChannel());
+ mRecordHighCallStyle.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
+ mRecordHighCallStyle.setInterruptive(true);
+
Notification n4 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.MessagingStyle("sender!")).build();
mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
@@ -236,6 +256,7 @@
final List<NotificationRecord> expected = new ArrayList<>();
expected.add(mRecordColorizedCall);
expected.add(mRecordColorized);
+ expected.add(mRecordHighCallStyle);
expected.add(mRecordHighCall);
expected.add(mRecordInlineReply);
if (mRecordSms != null) {
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 9826031..e6ac52d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -339,8 +339,8 @@
// Direct starter to use spy stack.
doReturn(stack).when(mRootWindowContainer)
.getLaunchRootTask(any(), any(), any(), anyBoolean());
- doReturn(stack).when(mRootWindowContainer).getLaunchRootTask(any(), any(), any(),
- anyBoolean(), any(), anyInt(), anyInt());
+ doReturn(stack).when(mRootWindowContainer).getLaunchRootTask(any(), any(), any(), any(),
+ anyBoolean(), any(), anyInt(), anyInt(), anyInt());
}
// Set up mock package manager internal and make sure no unmocked methods are called
@@ -1119,8 +1119,8 @@
stack.addChild(targetRecord);
- doReturn(stack).when(mRootWindowContainer)
- .getLaunchRootTask(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
+ doReturn(stack).when(mRootWindowContainer).getLaunchRootTask(any(), any(), any(), any(),
+ anyBoolean(), any(), anyInt(), anyInt(), anyInt());
starter.mStartActivity = new ActivityBuilder(mAtm).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 4dbb2de..e1eef762 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1244,7 +1244,6 @@
final DisplayContent displayContent = createNewDisplay();
Mockito.doReturn(mockLogger).when(displayContent).getMetricsLogger();
Mockito.doReturn(oldConfig).doReturn(newConfig).when(displayContent).getConfiguration();
- doNothing().when(displayContent).preOnConfigurationChanged();
displayContent.onConfigurationChanged(newConfig);
@@ -1321,6 +1320,8 @@
app.setRequestedOrientation(newOrientation);
assertTrue(app.isFixedRotationTransforming());
+ assertTrue(mAppWindow.matchesDisplayAreaBounds());
+ assertFalse(mAppWindow.isLetterboxedAppWindow());
assertTrue(mDisplayContent.getDisplayRotation().shouldRotateSeamlessly(
ROTATION_0 /* oldRotation */, ROTATION_90 /* newRotation */,
false /* forceUpdate */));
@@ -1458,54 +1459,51 @@
public void testFixedRotationWithPip() {
final DisplayContent displayContent = mDefaultDisplay;
unblockDisplayRotation(displayContent);
+ // Unblock the condition in PinnedTaskController#continueOrientationChangeIfNeeded.
+ doNothing().when(displayContent).prepareAppTransition(anyInt());
// Make resume-top really update the activity state.
- setBooted(mWm.mAtmService);
- // Speed up the test by a few seconds.
- mWm.mAtmService.deferWindowLayout();
- doNothing().when(mWm).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
-
- final Configuration displayConfig = displayContent.getConfiguration();
- final ActivityRecord pinnedActivity = createActivityRecord(displayContent,
- WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD);
- final Task pinnedTask = pinnedActivity.getRootTask();
- final ActivityRecord homeActivity = createActivityRecord(displayContent);
- if (displayConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
- homeActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
- pinnedActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- } else {
- homeActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- pinnedActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
- }
- final int homeConfigOrientation = homeActivity.getRequestedConfigurationOrientation();
- final int pinnedConfigOrientation = pinnedActivity.getRequestedConfigurationOrientation();
-
- assertEquals(homeConfigOrientation, displayConfig.orientation);
-
+ setBooted(mAtm);
clearInvocations(mWm);
+ // Speed up the test by a few seconds.
+ mAtm.deferWindowLayout();
+
+ final ActivityRecord homeActivity = createActivityRecord(
+ displayContent.getDefaultTaskDisplayArea().getRootHomeTask());
+ final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final Task pinnedTask = pinnedActivity.getRootTask();
+ doReturn((displayContent.getRotation() + 1) % 4).when(displayContent)
+ .rotationForActivityInDifferentOrientation(eq(homeActivity));
+ // Enter PiP from fullscreen.
+ pinnedTask.setWindowingMode(WINDOWING_MODE_PINNED);
+
+ assertTrue(displayContent.hasTopFixedRotationLaunchingApp());
+ assertTrue(displayContent.mPinnedTaskController.shouldDeferOrientationChange());
+ verify(mWm, never()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
+ clearInvocations(pinnedTask);
+
+ // Assume that the PiP enter animation is done then the new bounds are set. Expect the
+ // orientation update is no longer deferred.
+ displayContent.mPinnedTaskController.setEnterPipBounds(pinnedTask.getBounds());
+ // The Task Configuration was frozen to skip the change of orientation.
+ verify(pinnedTask, never()).onConfigurationChanged(any());
+ assertFalse(displayContent.mPinnedTaskController.shouldDeferOrientationChange());
+ assertFalse(displayContent.hasTopFixedRotationLaunchingApp());
+ assertEquals(homeActivity.getConfiguration().orientation,
+ displayContent.getConfiguration().orientation);
+
+ doReturn((displayContent.getRotation() + 1) % 4).when(displayContent)
+ .rotationForActivityInDifferentOrientation(eq(pinnedActivity));
// Leave PiP to fullscreen. Simulate the step of PipTaskOrganizer that sets the activity
// to fullscreen, so fixed rotation will apply on it.
pinnedActivity.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- homeActivity.setState(Task.ActivityState.STOPPED, "test");
-
assertTrue(displayContent.hasTopFixedRotationLaunchingApp());
- verify(mWm, never()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
- assertNotEquals(pinnedConfigOrientation, displayConfig.orientation);
// Assume the animation of PipTaskOrganizer is done and then commit fullscreen to task.
pinnedTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
displayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
- assertFalse(displayContent.getPinnedTaskController().isPipActiveOrWindowingModeChanging());
- assertEquals(pinnedConfigOrientation, displayConfig.orientation);
-
- clearInvocations(mWm);
- // Enter PiP from fullscreen. The orientation can be updated from
- // ensure-visibility/resume-focused-stack -> ActivityRecord#makeActiveIfNeeded -> resume.
- pinnedTask.setWindowingMode(WINDOWING_MODE_PINNED);
-
- assertFalse(displayContent.hasTopFixedRotationLaunchingApp());
- verify(mWm, atLeastOnce()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
- assertEquals(homeConfigOrientation, displayConfig.orientation);
- assertTrue(displayContent.getPinnedTaskController().isPipActiveOrWindowingModeChanging());
+ assertFalse(displayContent.mPinnedTaskController.isFreezingTaskConfig(pinnedTask));
+ assertEquals(pinnedActivity.getConfiguration().orientation,
+ displayContent.getConfiguration().orientation);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 2321a73..e1aca55 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -121,8 +121,6 @@
sMockWm = mock(WindowManagerService.class);
sMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class);
sMockWm.mPolicy = mock(WindowManagerPolicy.class);
- sMockWm.mConstants = mock(WindowManagerConstants.class);
- sMockWm.mConstants.mRawSensorLoggingEnabled = true;
}
@AfterClass
diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
index bdc4b4e..2c3f52e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
@@ -91,7 +91,7 @@
doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider();
// Display: 1920x1200 (landscape). First and second display are both 860x1200 (portrait).
- mDisplay = (DualDisplayContent) new DualDisplayContent.Builder(mAtm, 1920, 1200).build();
+ mDisplay = new DualDisplayContent.Builder(mAtm, 1920, 1200).build();
mFirstRoot = mDisplay.mFirstRoot;
mSecondRoot = mDisplay.mSecondRoot;
mFirstTda = mDisplay.getTaskDisplayArea(FEATURE_FIRST_TASK_CONTAINER);
@@ -395,7 +395,7 @@
}
/** Display with two {@link DisplayAreaGroup}. Each of them take half of the screen. */
- private static class DualDisplayContent extends TestDisplayContent {
+ static class DualDisplayContent extends TestDisplayContent {
final DisplayAreaGroup mFirstRoot;
final DisplayAreaGroup mSecondRoot;
final Rect mLastDisplayBounds;
@@ -476,11 +476,15 @@
TestDisplayContent createInternal(Display display) {
return new DualDisplayContent(mService.mRootWindowContainer, display);
}
+
+ DualDisplayContent build() {
+ return (DualDisplayContent) super.build();
+ }
}
}
/** Policy to create a dual {@link DisplayAreaGroup} policy in test. */
- private static class DualDisplayTestPolicyProvider implements DisplayAreaPolicy.Provider {
+ static class DualDisplayTestPolicyProvider implements DisplayAreaPolicy.Provider {
@Override
public DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content,
diff --git a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
index 1b9308d..f2418c6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
@@ -47,6 +47,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
// TODO(b/157888351): Move the test to inputmethod package once we find the way to test the
// scenario there.
@@ -59,10 +60,15 @@
public class InputMethodMenuControllerTest extends WindowTestsBase {
private InputMethodMenuController mController;
- private TestDisplayContent mSecondaryDisplay;
+ private DualDisplayAreaGroupPolicyTest.DualDisplayContent mSecondaryDisplay;
@Before
public void setUp() throws Exception {
+ // Let the Display to be created with the DualDisplay policy.
+ final DisplayAreaPolicy.Provider policyProvider =
+ new DualDisplayAreaGroupPolicyTest.DualDisplayTestPolicyProvider();
+ Mockito.doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider();
+
mController = new InputMethodMenuController(mock(InputMethodManagerService.class));
// Mock addWindowTokenWithOptions to create a test window token.
@@ -80,7 +86,8 @@
}).when(wms).attachWindowContextToDisplayArea(any(), eq(TYPE_INPUT_METHOD_DIALOG),
anyInt(), any());
- mSecondaryDisplay = new TestDisplayContent.Builder(mAtm, 1000, 1000).build();
+ mSecondaryDisplay = new DualDisplayAreaGroupPolicyTest.DualDisplayContent
+ .Builder(mAtm, 1000, 1000).build();
// Mock DisplayManagerGlobal to return test display when obtaining Display instance.
final int displayId = mSecondaryDisplay.getDisplayId();
@@ -105,6 +112,22 @@
assertImeSwitchContextMetricsValidity(contextOnSecondaryDisplay, mSecondaryDisplay);
}
+ @Test
+ public void testGetSettingsContextOnDualDisplayContent() {
+ final Context context = mController.getSettingsContext(mSecondaryDisplay.getDisplayId());
+
+ final DisplayArea.Tokens imeContainer = mSecondaryDisplay.getImeContainer();
+ assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mSecondaryDisplay);
+
+ mSecondaryDisplay.mFirstRoot.placeImeContainer(imeContainer);
+ assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mSecondaryDisplay.mFirstRoot);
+ assertImeSwitchContextMetricsValidity(context, mSecondaryDisplay);
+
+ mSecondaryDisplay.mSecondRoot.placeImeContainer(imeContainer);
+ assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mSecondaryDisplay.mSecondRoot);
+ assertImeSwitchContextMetricsValidity(context, mSecondaryDisplay);
+ }
+
private void assertImeSwitchContextMetricsValidity(Context context, DisplayContent dc) {
assertThat(context.getDisplayId()).isEqualTo(dc.getDisplayId());
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 37da529..b6cfa8e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -177,7 +177,7 @@
mFinishedCallback);
mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
- mClock.fastForward(2500);
+ mClock.fastForward(10500);
mHandler.timeAdvance();
verify(mMockRunner).onAnimationCancelled();
@@ -198,12 +198,12 @@
mFinishedCallback);
mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
- mClock.fastForward(2500);
+ mClock.fastForward(10500);
mHandler.timeAdvance();
verify(mMockRunner, never()).onAnimationCancelled();
- mClock.fastForward(10000);
+ mClock.fastForward(52500);
mHandler.timeAdvance();
verify(mMockRunner).onAnimationCancelled();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 0bf237d..4f5511b5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -980,7 +980,8 @@
doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId,
300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info);
final Task result = mRootWindowContainer.getLaunchRootTask(r, options,
- null /* task */, true /* onTop */, null, 300 /* test realCallerPid */,
+ null /* task */, null /* sourceTask */, true /* onTop */, null /* launchParams */,
+ 0 /* launchFlags */, 300 /* test realCallerPid */,
300 /* test realCallerUid */);
// Assert that the root task is returned as expected.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index 92d4ede..9289ce4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -28,6 +28,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
@@ -75,6 +76,52 @@
public class TaskDisplayAreaTests extends WindowTestsBase {
@Test
+ public void getLaunchRootTask_checksLaunchAdjacentFlagRoot() {
+ final Task rootTask = createTask(
+ mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
+ rootTask.mCreatedByOrganizer = true;
+ final Task adjacentRootTask = createTask(
+ mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
+ adjacentRootTask.mCreatedByOrganizer = true;
+ final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea();
+ adjacentRootTask.mAdjacentTask = rootTask;
+ rootTask.mAdjacentTask = adjacentRootTask;
+
+ taskDisplayArea.setLaunchAdjacentFlagRootTask(adjacentRootTask);
+ Task actualRootTask = taskDisplayArea.getLaunchRootTask(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, null /* options */,
+ null /* sourceTask */, FLAG_ACTIVITY_LAUNCH_ADJACENT);
+ assertSame(adjacentRootTask, actualRootTask.getRootTask());
+
+ taskDisplayArea.setLaunchAdjacentFlagRootTask(null);
+ actualRootTask = taskDisplayArea.getLaunchRootTask(WINDOWING_MODE_UNDEFINED,
+ ACTIVITY_TYPE_STANDARD, null /* options */, null /* sourceTask */,
+ FLAG_ACTIVITY_LAUNCH_ADJACENT);
+ assertNull(actualRootTask);
+ }
+
+ @Test
+ public void getLaunchRootTask_fromLaunchAdjacentFlagRoot_checksAdjacentRoot() {
+ final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent);
+ final Task rootTask = createTask(
+ mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
+ rootTask.mCreatedByOrganizer = true;
+ final Task adjacentRootTask = createTask(
+ mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
+ adjacentRootTask.mCreatedByOrganizer = true;
+ final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea();
+ adjacentRootTask.mAdjacentTask = rootTask;
+ rootTask.mAdjacentTask = adjacentRootTask;
+
+ taskDisplayArea.setLaunchAdjacentFlagRootTask(adjacentRootTask);
+ final Task actualRootTask = taskDisplayArea.getLaunchRootTask(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, null /* options */,
+ adjacentRootTask /* sourceTask */, FLAG_ACTIVITY_LAUNCH_ADJACENT);
+
+ assertSame(rootTask, actualRootTask.getRootTask());
+ }
+
+ @Test
public void getOrCreateLaunchRootRespectsResolvedWindowingMode() {
final Task rootTask = createTask(
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
@@ -90,8 +137,8 @@
launchParams.mWindowingMode = WINDOWING_MODE_FREEFORM;
final Task actualRootTask = taskDisplayArea.getOrCreateRootTask(
- activity, null /* options */, candidateRootTask,
- launchParams, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ activity, null /* options */, candidateRootTask, null /* sourceTask */,
+ launchParams, 0 /* launchFlags */, ACTIVITY_TYPE_STANDARD, true /* onTop */);
assertSame(rootTask, actualRootTask.getRootTask());
}
@@ -111,8 +158,9 @@
options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
final Task actualRootTask = taskDisplayArea.getOrCreateRootTask(
- activity, options, candidateRootTask,
- null /* launchParams */, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ activity, options, candidateRootTask, null /* sourceTask */,
+ null /* launchParams */, 0 /* launchFlags */, ACTIVITY_TYPE_STANDARD,
+ true /* onTop */);
assertSame(rootTask, actualRootTask.getRootTask());
}
@@ -458,8 +506,8 @@
boolean reuseCandidate) {
final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea();
final Task rootTask = taskDisplayArea.getOrCreateRootTask(windowingMode, activityType,
- false /* onTop */, null /* intent */, candidateTask /* candidateTask */,
- null /* activityOptions */);
+ false /* onTop */, candidateTask /* candidateTask */, null /* sourceTask */,
+ null /* activityOptions */, 0 /* launchFlags */);
assertEquals(reuseCandidate, rootTask == candidateTask);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java
index 212ffd5..0b1b877 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java
@@ -18,14 +18,13 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-import static org.mockito.ArgumentMatchers.any;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
import android.hardware.HardwareBuffer;
import android.platform.test.annotations.Presubmit;
-import android.view.Surface;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
@@ -51,8 +50,8 @@
when(mockAr.getPendingTransaction()).thenReturn(new StubTransaction());
when(mockAr.makeChildSurface(any())).thenReturn(new MockSurfaceControlBuilder());
when(mockAr.makeSurface()).thenReturn(new MockSurfaceControlBuilder());
- return new WindowContainerThumbnail(new StubTransaction(), mockAr,
- buffer, false, mock(Surface.class), mock(SurfaceAnimator.class));
+ return new WindowContainerThumbnail(new StubTransaction(), mockAr, buffer,
+ mock(SurfaceAnimator.class));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index bfbe203..8d067be 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -47,6 +48,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL;
import static com.android.server.wm.WindowContainer.SYNC_STATE_WAITING_FOR_DRAW;
import static com.google.common.truth.Truth.assertThat;
@@ -877,4 +879,30 @@
mDisplayContent.getInsetsStateController().notifyInsetsChanged();
verify(app).notifyInsetsChanged();
}
+
+ @UseTestDisplay(addWindows = { W_ACTIVITY })
+ @Test
+ public void testUpdateImeControlTargetWhenLeavingMultiWindow() {
+ WindowState app = createWindow(null, TYPE_BASE_APPLICATION,
+ mAppWindow.mToken, "app");
+ mDisplayContent.setRemoteInsetsController(createDisplayWindowInsetsController());
+
+ spyOn(app);
+ mDisplayContent.setImeInputTarget(mAppWindow);
+ mDisplayContent.setImeLayeringTarget(mAppWindow);
+
+ // Simulate entering multi-window mode and verify if the IME control target is remote.
+ app.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, app.getWindowingMode());
+ assertEquals(mDisplayContent.mRemoteInsetsControlTarget,
+ mDisplayContent.computeImeControlTarget());
+
+ // Simulate exiting multi-window mode and verify if the IME control target changed
+ // to the app window.
+ spyOn(app.getDisplayContent());
+ app.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ verify(app.getDisplayContent()).updateImeControlTarget();
+ assertEquals(mAppWindow, mDisplayContent.getImeTarget(IME_TARGET_CONTROL).getWindow());
+ }
}
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java
index 6bba65d..628f8cd 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerService.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java
@@ -44,6 +44,7 @@
import android.view.translation.TranslationContext;
import android.view.translation.TranslationSpec;
import android.view.translation.UiTranslationManager.UiTranslationState;
+import android.view.translation.UiTranslationSpec;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.IResultReceiver;
@@ -170,6 +171,28 @@
}
@Override
+ public void registerTranslationCapabilityCallback(IRemoteCallback callback, int userId) {
+ TranslationManagerServiceImpl service;
+ synchronized (mLock) {
+ service = getServiceForUserLocked(userId);
+ }
+ if (service != null) {
+ service.registerTranslationCapabilityCallback(callback, Binder.getCallingUid());
+ }
+ }
+
+ @Override
+ public void unregisterTranslationCapabilityCallback(IRemoteCallback callback, int userId) {
+ TranslationManagerServiceImpl service;
+ synchronized (mLock) {
+ service = getServiceForUserLocked(userId);
+ }
+ if (service != null) {
+ service.unregisterTranslationCapabilityCallback(callback);
+ }
+ }
+
+ @Override
public void onSessionCreated(TranslationContext translationContext,
int sessionId, IResultReceiver receiver, int userId) throws RemoteException {
synchronized (mLock) {
@@ -187,14 +210,14 @@
@Override
public void updateUiTranslationState(@UiTranslationState int state,
TranslationSpec sourceSpec, TranslationSpec targetSpec, List<AutofillId> viewIds,
- IBinder token, int taskId, int userId) {
+ IBinder token, int taskId, UiTranslationSpec uiTranslationSpec, int userId) {
enforceCallerHasPermission(MANAGE_UI_TRANSLATION);
synchronized (mLock) {
final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
if (service != null && (isDefaultServiceLocked(userId)
|| isCalledByServiceAppLocked(userId, "updateUiTranslationState"))) {
service.updateUiTranslationStateLocked(state, sourceSpec, targetSpec, viewIds,
- token, taskId);
+ token, taskId, uiTranslationSpec);
}
}
}
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
index be9e0ec..4198d3b 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
@@ -41,6 +41,7 @@
import android.view.translation.TranslationContext;
import android.view.translation.TranslationSpec;
import android.view.translation.UiTranslationManager.UiTranslationState;
+import android.view.translation.UiTranslationSpec;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.IResultReceiver;
@@ -142,6 +143,15 @@
}
}
+ public void registerTranslationCapabilityCallback(IRemoteCallback callback, int sourceUid) {
+ mTranslationCapabilityCallbacks.register(callback, sourceUid);
+ ensureRemoteServiceLocked();
+ }
+
+ public void unregisterTranslationCapabilityCallback(IRemoteCallback callback) {
+ mTranslationCapabilityCallbacks.unregister(callback);
+ }
+
@GuardedBy("mLock")
void onSessionCreatedLocked(@NonNull TranslationContext translationContext, int sessionId,
IResultReceiver resultReceiver) {
@@ -154,7 +164,7 @@
@GuardedBy("mLock")
public void updateUiTranslationStateLocked(@UiTranslationState int state,
TranslationSpec sourceSpec, TranslationSpec targetSpec, List<AutofillId> viewIds,
- IBinder token, int taskId) {
+ IBinder token, int taskId, UiTranslationSpec uiTranslationSpec) {
// Get top activity for a given task id
final ActivityTokens taskTopActivityTokens =
mActivityTaskManagerInternal.getTopActivityForTask(taskId);
@@ -165,6 +175,7 @@
return;
}
try {
+ // TODO: Pipe uiTranslationSpec through to the UiTranslationController.
taskTopActivityTokens.getApplicationThread().updateUiTranslationState(
taskTopActivityTokens.getActivityToken(), state, sourceSpec, targetSpec,
viewIds);
diff --git a/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java b/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java
index 2f6a2b0..f34567f 100644
--- a/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java
+++ b/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java
@@ -311,6 +311,11 @@
}
@Override
+ public synchronized int getAdapterState() throws RemoteException {
+ return getVendorUwbAdapter().getAdapterState();
+ }
+
+ @Override
public synchronized void setEnabled(boolean enabled) throws RemoteException {
getVendorUwbAdapter().setEnabled(enabled);
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index d6ed98f..3fbd40f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -65,7 +65,6 @@
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -235,19 +234,32 @@
Slog.d(TAG, "startListeningFromMic");
}
- AudioRecord audioRecord = createMicAudioRecord(audioFormat);
- if (audioRecord == null) {
- // TODO: Callback.onError();
- return;
- }
+ // TODO: consider making this a non-anonymous class.
+ IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() {
+ @Override
+ public void onDetected(HotwordDetectedResult result) throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "onDetected");
+ }
+ callback.onDetected(result, null, null);
+ }
- handleSoftwareHotwordDetection(
- audioFormat,
- AudioReader.createFromAudioRecord(audioRecord),
- AUDIO_SOURCE_MICROPHONE,
- // TODO: handle bundles better.
- new PersistableBundle(),
- callback);
+ @Override
+ public void onRejected(HotwordRejectedResult result) throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "onRejected");
+ }
+ // onRejected isn't allowed here
+ }
+ };
+
+ mRemoteHotwordDetectionService.run(
+ service -> service.detectFromMicrophoneSource(
+ null,
+ AUDIO_SOURCE_MICROPHONE,
+ null,
+ null,
+ internalCallback));
}
public void startListeningFromExternalSource(
@@ -298,74 +310,12 @@
if (DEBUG) {
Slog.d(TAG, "detectFromDspSourceForTest");
}
-
- AudioRecord record = createFakeAudioRecord();
- if (record == null) {
- Slog.d(TAG, "Failed to create fake audio record");
- return;
- }
-
- Pair<ParcelFileDescriptor, ParcelFileDescriptor> clientPipe = createPipe();
- if (clientPipe == null) {
- Slog.d(TAG, "Failed to create pipe");
- return;
- }
- ParcelFileDescriptor audioSink = clientPipe.second;
- ParcelFileDescriptor clientRead = clientPipe.first;
-
- record.startRecording();
-
- mAudioCopyExecutor.execute(() -> {
- try (OutputStream fos =
- new ParcelFileDescriptor.AutoCloseOutputStream(audioSink)) {
-
- int remainToRead = 10240;
- byte[] buffer = new byte[1024];
- while (remainToRead > 0) {
- int bytesRead = record.read(buffer, 0, 1024);
- if (DEBUG) {
- Slog.d(TAG, "bytesRead = " + bytesRead);
- }
- if (bytesRead <= 0) {
- break;
- }
- if (bytesRead > 8) {
- System.arraycopy(new byte[] {'h', 'o', 't', 'w', 'o', 'r', 'd', '!'}, 0,
- buffer, 0, 8);
- }
-
- fos.write(buffer, 0, bytesRead);
- remainToRead -= bytesRead;
- }
- } catch (IOException e) {
- Slog.w(TAG, "Failed supplying audio data to validator", e);
- }
- });
-
- Runnable cancellingJob = () -> {
- Slog.d(TAG, "Timeout for getting callback from HotwordDetectionService");
- record.stop();
- record.release();
- bestEffortClose(audioSink);
- bestEffortClose(clientRead);
- };
-
- ScheduledFuture<?> cancelingFuture =
- mScheduledExecutorService.schedule(
- cancellingJob, VALIDATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
-
IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() {
@Override
public void onDetected(HotwordDetectedResult result) throws RemoteException {
if (DEBUG) {
Slog.d(TAG, "onDetected");
}
- cancelingFuture.cancel(true);
- record.stop();
- record.release();
- bestEffortClose(audioSink);
- bestEffortClose(clientRead);
-
externalCallback.onKeyphraseDetected(recognitionEvent);
}
@@ -374,19 +324,13 @@
if (DEBUG) {
Slog.d(TAG, "onRejected");
}
- cancelingFuture.cancel(true);
- record.stop();
- record.release();
- bestEffortClose(audioSink);
- bestEffortClose(clientRead);
-
externalCallback.onRejected(result);
}
};
mRemoteHotwordDetectionService.run(
service -> service.detectFromDspSource(
- clientRead,
+ recognitionEvent,
recognitionEvent.getCaptureFormat(),
VALIDATION_TIMEOUT_MILLIS,
internalCallback));
@@ -398,49 +342,6 @@
Slog.d(TAG, "detectFromDspSource");
}
- AudioRecord record = createAudioRecord(recognitionEvent);
-
- Pair<ParcelFileDescriptor, ParcelFileDescriptor> clientPipe = createPipe();
-
- if (clientPipe == null) {
- // Error.
- // Need to propagate as unknown error or something?
- return;
- }
- ParcelFileDescriptor audioSink = clientPipe.second;
- ParcelFileDescriptor clientRead = clientPipe.first;
-
- record.startRecording();
-
- mAudioCopyExecutor.execute(() -> {
- try (OutputStream fos =
- new ParcelFileDescriptor.AutoCloseOutputStream(audioSink)) {
- byte[] buffer = new byte[1024];
-
- while (true) {
- int bytesRead = record.read(buffer, 0, 1024);
-
- if (bytesRead < 0) {
- break;
- }
-
- fos.write(buffer, 0, bytesRead);
- }
- } catch (IOException e) {
- Slog.w(TAG, "Failed supplying audio data to validator", e);
- }
- });
-
- Runnable cancellingJob = () -> {
- record.stop();
- bestEffortClose(audioSink);
- // TODO: consider calling externalCallback.onRejected(ERROR_TIMEOUT).
- };
-
- ScheduledFuture<?> cancelingFuture =
- mScheduledExecutorService.schedule(
- cancellingJob, VALIDATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
-
// TODO: consider making this a non-anonymous class.
IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() {
@Override
@@ -448,18 +349,6 @@
if (DEBUG) {
Slog.d(TAG, "onDetected");
}
- bestEffortClose(audioSink);
- cancelingFuture.cancel(true);
-
- // Give 2 more seconds for the interactor to start consuming the mic. If it fails to
- // do so under the given time, we'll force-close the mic to make sure resources are
- // freed up.
- // TODO: consider modelling these 2 seconds in the API.
- mScheduledExecutorService.schedule(
- cancellingJob,
- VOICE_INTERACTION_TIMEOUT_TO_OPEN_MIC_MILLIS,
- TimeUnit.MILLISECONDS);
-
// TODO: Propagate the HotwordDetectedResult.
externalCallback.onKeyphraseDetected(recognitionEvent);
}
@@ -469,18 +358,16 @@
if (DEBUG) {
Slog.d(TAG, "onRejected");
}
- cancelingFuture.cancel(true);
externalCallback.onRejected(result);
}
};
mRemoteHotwordDetectionService.run(
service -> service.detectFromDspSource(
- clientRead,
+ recognitionEvent,
recognitionEvent.getCaptureFormat(),
VALIDATION_TIMEOUT_MILLIS,
internalCallback));
- bestEffortClose(clientRead);
}
static final class SoundTriggerCallback extends IRecognitionStatusCallback.Stub {
diff --git a/telephony/java/android/telephony/ims/RcsConfig.java b/telephony/java/android/telephony/ims/RcsConfig.java
index d7c3f98..6867c86 100644
--- a/telephony/java/android/telephony/ims/RcsConfig.java
+++ b/telephony/java/android/telephony/ims/RcsConfig.java
@@ -22,10 +22,10 @@
import android.content.Context;
import android.database.Cursor;
import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.provider.Telephony.SimInfo;
import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import com.android.telephony.Rlog;
@@ -36,7 +36,9 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@@ -44,27 +46,138 @@
* RCS config data and methods to process the config
* @hide
*/
-public final class RcsConfig implements Parcelable {
+public final class RcsConfig {
private static final String LOG_TAG = "RcsConfig";
private static final boolean DBG = Build.IS_ENG;
// Tag and attribute defined in RCC.07 A.2
+ private static final String TAG_CHARACTERISTIC = "characteristic";
private static final String TAG_PARM = "parm";
+ private static final String ATTRIBUTE_TYPE = "type";
private static final String ATTRIBUTE_NAME = "name";
private static final String ATTRIBUTE_VALUE = "value";
// Keyword for Rcs Volte single registration defined in RCC.07 A.1.6.2
private static final String PARM_SINGLE_REGISTRATION = "rcsVolteSingleRegistration";
- private final HashMap<String, String> mValues = new HashMap<>();
+ /**
+ * Characteristic of the RCS provisioning config
+ */
+ public static class Characteristic {
+ private String mType;
+ private final Map<String, String> mParms = new ArrayMap<>();
+ private final Set<Characteristic> mSubs = new ArraySet<>();
+ private final Characteristic mParent;
- private RcsConfig(HashMap<String, String> values) {
- mValues.putAll(values);
+ private Characteristic(String type, Characteristic parent) {
+ mType = type;
+ mParent = parent;
+ }
+
+ private String getType() {
+ return mType;
+ }
+
+ private Map<String, String> getParms() {
+ return mParms;
+ }
+
+ private Set<Characteristic> getSubs() {
+ return mSubs;
+ }
+
+ private Characteristic getParent() {
+ return mParent;
+ }
+
+ private Characteristic getSubByType(String type) {
+ if (TextUtils.equals(mType, type)) {
+ return this;
+ }
+ Characteristic result = null;
+ for (Characteristic sub : mSubs) {
+ result = sub.getSubByType(type);
+ if (result != null) {
+ break;
+ }
+ }
+ return result;
+ }
+
+ private boolean hasSubByType(String type) {
+ return getSubByType(type) != null;
+ }
+
+ private String getParmValue(String name) {
+ String value = mParms.get(name);
+ if (value == null) {
+ for (Characteristic sub : mSubs) {
+ value = sub.getParmValue(name);
+ if (value != null) {
+ break;
+ }
+ }
+ }
+ return value;
+ }
+
+ boolean hasParm(String name) {
+ if (mParms.containsKey(name)) {
+ return true;
+ }
+
+ for (Characteristic sub : mSubs) {
+ if (sub.hasParm(name)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("[" + mType + "]: ");
+ if (DBG) {
+ sb.append(mParms);
+ }
+ for (Characteristic sub : mSubs) {
+ sb.append("\n");
+ sb.append(sub.toString().replace("\n", "\n\t"));
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Characteristic)) {
+ return false;
+ }
+
+ Characteristic o = (Characteristic) obj;
+
+ return TextUtils.equals(mType, o.mType) && mParms.equals(o.mParms)
+ && mSubs.equals(o.mSubs);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mType, mParms, mSubs);
+ }
}
+ private final Characteristic mRoot;
+ private Characteristic mCurrent;
+ private final byte[] mData;
+
public RcsConfig(byte[] data) throws IllegalArgumentException {
if (data == null || data.length == 0) {
throw new IllegalArgumentException("Empty data");
}
+ mRoot = new Characteristic(null, null);
+ mCurrent = mRoot;
+ mData = data;
+ Characteristic current = mRoot;
ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
@@ -73,36 +186,51 @@
xpp.setInput(inputStream, null);
int eventType = xpp.getEventType();
String tag = null;
- while (eventType != XmlPullParser.END_DOCUMENT) {
+ while (eventType != XmlPullParser.END_DOCUMENT && current != null) {
if (eventType == XmlPullParser.START_TAG) {
tag = xpp.getName().trim().toLowerCase();
- if (tag.equals(TAG_PARM)) {
+ if (TAG_CHARACTERISTIC.equals(tag)) {
+ int count = xpp.getAttributeCount();
+ String type = null;
+ if (count > 0) {
+ for (int i = 0; i < count; i++) {
+ String name = xpp.getAttributeName(i).trim().toLowerCase();
+ if (ATTRIBUTE_TYPE.equals(name)) {
+ type = xpp.getAttributeValue(xpp.getAttributeNamespace(i),
+ name).trim().toLowerCase();
+ break;
+ }
+ }
+ }
+ Characteristic next = new Characteristic(type, current);
+ current.getSubs().add(next);
+ current = next;
+ } else if (TAG_PARM.equals(tag)) {
int count = xpp.getAttributeCount();
String key = null;
String value = null;
if (count > 1) {
for (int i = 0; i < count; i++) {
String name = xpp.getAttributeName(i).trim().toLowerCase();
- if (name.equals(ATTRIBUTE_NAME)) {
+ if (ATTRIBUTE_NAME.equals(name)) {
key = xpp.getAttributeValue(xpp.getAttributeNamespace(i),
name).trim().toLowerCase();
- } else if (name.equals(ATTRIBUTE_VALUE)) {
+ } else if (ATTRIBUTE_VALUE.equals(name)) {
value = xpp.getAttributeValue(xpp.getAttributeNamespace(i),
name).trim();
}
}
}
if (key != null && value != null) {
- mValues.put(key, value);
+ current.getParms().put(key, value);
}
}
} else if (eventType == XmlPullParser.END_TAG) {
- tag = null;
- } else if (eventType == XmlPullParser.TEXT) {
- String value = xpp.getText().trim();
- if (!TextUtils.isEmpty(tag) && !TextUtils.isEmpty(value)) {
- mValues.put(tag, value);
+ tag = xpp.getName().trim().toLowerCase();
+ if (TAG_CHARACTERISTIC.equals(tag)) {
+ current = current.getParent();
}
+ tag = null;
}
eventType = xpp.next();
}
@@ -126,8 +254,8 @@
* @return Returns the config value if it exists, or defaultVal.
*/
public @Nullable String getString(@NonNull String tag, @Nullable String defaultVal) {
- tag = tag.trim().toLowerCase();
- return mValues.containsKey(tag) ? mValues.get(tag) : defaultVal;
+ String value = mCurrent.getParmValue(tag.trim().toLowerCase());
+ return value != null ? value : defaultVal;
}
/**
@@ -139,9 +267,8 @@
* @return Returns the config value if it exists and is a valid int, or defaultVal.
*/
public int getInteger(@NonNull String tag, int defaultVal) {
- tag = tag.trim().toLowerCase();
try {
- return Integer.parseInt(mValues.get(tag));
+ return Integer.parseInt(getString(tag, null));
} catch (NumberFormatException e) {
logd("error to getInteger for " + tag + " due to " + e);
}
@@ -157,11 +284,8 @@
* @return Returns the config value if it exists, or defaultVal.
*/
public boolean getBoolean(@NonNull String tag, boolean defaultVal) {
- tag = tag.trim().toLowerCase();
- if (!mValues.containsKey(tag)) {
- return defaultVal;
- }
- return Boolean.parseBoolean(mValues.get(tag));
+ String value = getString(tag, null);
+ return value != null ? Boolean.parseBoolean(value) : defaultVal;
}
/**
@@ -172,7 +296,62 @@
* @return Returns true if it exists, or false.
*/
public boolean hasConfig(@NonNull String tag) {
- return mValues.containsKey(tag.trim().toLowerCase());
+ return mCurrent.hasParm(tag.trim().toLowerCase());
+ }
+
+ /**
+ * Return the Characteristic with the given type
+ */
+ public @Nullable Characteristic getCharacteristic(@NonNull String type) {
+ return mCurrent.getSubByType(type.trim().toLowerCase());
+ }
+
+ /**
+ * Check whether the Characteristic with the given type exists
+ */
+ public boolean hasCharacteristic(@NonNull String type) {
+ return mCurrent.getSubByType(type.trim().toLowerCase()) != null;
+ }
+
+ /**
+ * Set current Characteristic to given Characteristic
+ */
+ public void setCurrentCharacteristic(@NonNull Characteristic current) {
+ if (current != null) {
+ mCurrent = current;
+ }
+ }
+
+ /**
+ * Move current Characteristic to parent layer
+ */
+ public boolean moveToParent() {
+ if (mCurrent.getParent() == null) {
+ return false;
+ }
+ mCurrent = mCurrent.getParent();
+ return true;
+ }
+
+ /**
+ * Move current Characteristic to the root
+ */
+ public void moveToRoot() {
+ mCurrent = mRoot;
+ }
+
+ /**
+ * Return root Characteristic
+ */
+ public @NonNull Characteristic getRoot() {
+ return mRoot;
+ }
+
+ /**
+ * Return current Characteristic
+ */
+ public @NonNull Characteristic getCurrentCharacteristic() {
+ return mCurrent;
}
/**
@@ -188,12 +367,10 @@
final StringBuilder sb = new StringBuilder();
sb.append("[RCS Config]");
if (DBG) {
- mValues.forEach((t, v) -> {
- sb.append("\n");
- sb.append(t);
- sb.append(" : ");
- sb.append(v);
- });
+ sb.append("=== Root ===\n");
+ sb.append(mRoot);
+ sb.append("=== Current ===\n");
+ sb.append(mCurrent);
}
return sb.toString();
}
@@ -206,12 +383,12 @@
RcsConfig other = (RcsConfig) obj;
- return mValues.equals(other.mValues);
+ return mRoot.equals(other.mRoot) && mCurrent.equals(other.mCurrent);
}
@Override
public int hashCode() {
- return mValues.hashCode();
+ return Objects.hash(mRoot, mCurrent);
}
/**
@@ -302,38 +479,6 @@
return isCompressed ? data : decompressGzip(data);
}
- /**
- * {@link Parcelable#writeToParcel}
- */
- public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeMap(mValues);
- }
-
- /**
- * {@link Parcelable.Creator}
- *
- */
- public static final @NonNull Parcelable.Creator<RcsConfig>
- CREATOR = new Creator<RcsConfig>() {
- @Override
- public RcsConfig createFromParcel(Parcel in) {
- HashMap<String, String> values = in.readHashMap(null);
- return values == null ? null : new RcsConfig(values);
- }
-
- @Override
- public RcsConfig[] newArray(int size) {
- return new RcsConfig[size];
- }
- };
-
- /**
- * {@link Parcelable#describeContents}
- */
- public int describeContents() {
- return 0;
- }
-
private static void logd(String msg) {
Rlog.d(LOG_TAG, msg);
}
diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java
index ca01d0f..aa2e6b9 100644
--- a/telephony/java/android/telephony/ims/SipDelegateManager.java
+++ b/telephony/java/android/telephony/ims/SipDelegateManager.java
@@ -34,6 +34,7 @@
import android.telephony.ims.stub.DelegateConnectionMessageCallback;
import android.telephony.ims.stub.DelegateConnectionStateCallback;
import android.telephony.ims.stub.SipDelegate;
+import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
@@ -163,6 +164,35 @@
})
public @interface MessageFailureReason {}
+ /**@hide*/
+ public static final ArrayMap<Integer, String> MESSAGE_FAILURE_REASON_STRING_MAP =
+ new ArrayMap<>(11);
+ static {
+ MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_UNKNOWN,
+ "MESSAGE_FAILURE_REASON_UNKNOWN");
+ MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_DELEGATE_DEAD,
+ "MESSAGE_FAILURE_REASON_DELEGATE_DEAD");
+ MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
+ "MESSAGE_FAILURE_REASON_DELEGATE_CLOSED");
+ MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS,
+ "MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS");
+ MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT,
+ "MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT");
+ MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG,
+ "MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG");
+ MESSAGE_FAILURE_REASON_STRING_MAP.append(
+ MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE,
+ "MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE");
+ MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE,
+ "MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE");
+ MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_NOT_REGISTERED,
+ "MESSAGE_FAILURE_REASON_NOT_REGISTERED");
+ MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION,
+ "MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION");
+ MESSAGE_FAILURE_REASON_STRING_MAP.append(
+ MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION,
+ "MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION");
+ }
/**
* Access to use this feature tag has been denied for an unknown reason.
diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.mk b/tests/DynamicCodeLoggerIntegrationTests/Android.mk
index bfb5b07..dab8304 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/Android.mk
+++ b/tests/DynamicCodeLoggerIntegrationTests/Android.mk
@@ -89,4 +89,7 @@
$(dynamiccodeloggertest_jar) \
$(dynamiccodeloggertest_executable) \
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
include $(BUILD_PACKAGE)
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index 8be3b7e..c06f8fd 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -60,7 +60,7 @@
private float mShaderParam1 = 0.0f;
static final String sSkSL =
- "in shader bitmapShader;\n"
+ "uniform shader bitmapShader;\n"
+ "uniform float param1;\n"
+ "half4 main(float2 xy) {\n"
+ " return half4(sample(bitmapShader, xy).rgb, param1);\n"
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
index 487c856..79410cf 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
@@ -89,7 +89,7 @@
+ " d = rand(float2(x, y)) > density ? d : d * .2;\n"
+ " d = d * rand(float2(fraction, x * y));\n"
+ " float alpha = 1. - pow(fraction, 3.);\n"
- + " return float4(sample(in_paintColor).rgb, d * alpha);\n"
+ + " return float4(sample(in_paintColor, p).rgb, d * alpha);\n"
+ "}";
RippleView(Context c) {
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
index 912aee6..ade94a9 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
@@ -440,7 +440,7 @@
}
}
- private static final String SKSL = "in shader uContentTexture;\n"
+ private static final String SKSL = "uniform shader uContentTexture;\n"
+ "uniform float uMaxStretchIntensity; // multiplier to apply to scale effect\n"
+ "uniform float uStretchAffectedDist; // Maximum percentage to stretch beyond bounds"
+ " of target\n"
diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk
index 9b155c9..b6f3471 100644
--- a/tests/backup/Android.mk
+++ b/tests/backup/Android.mk
@@ -47,4 +47,7 @@
LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
include $(BUILD_PACKAGE)
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index 64b774c..ab6b2f4 100644
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -31,11 +31,16 @@
import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD
import android.net.NetworkTemplate.MATCH_WIFI
import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD
+import android.net.NetworkTemplate.WIFI_NETWORKID_ALL
import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA
import android.net.NetworkTemplate.NETWORK_TYPE_ALL
import android.net.NetworkTemplate.OEM_MANAGED_ALL
import android.net.NetworkTemplate.OEM_MANAGED_NO
import android.net.NetworkTemplate.OEM_MANAGED_YES
+import android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT
+import android.net.NetworkTemplate.buildTemplateWifi
+import android.net.NetworkTemplate.buildTemplateWifiWildcard
+import android.net.NetworkTemplate.buildTemplateCarrier
import android.net.NetworkTemplate.buildTemplateMobileWithRatType
import android.telephony.TelephonyManager
import com.android.testutils.assertParcelSane
@@ -53,6 +58,7 @@
private const val TEST_IMSI1 = "imsi1"
private const val TEST_IMSI2 = "imsi2"
private const val TEST_SSID1 = "ssid1"
+private const val TEST_SSID2 = "ssid2"
@RunWith(JUnit4::class)
class NetworkTemplateTest {
@@ -60,8 +66,8 @@
private fun buildMobileNetworkState(subscriberId: String): NetworkStateSnapshot =
buildNetworkState(TYPE_MOBILE, subscriberId = subscriberId)
- private fun buildWifiNetworkState(ssid: String): NetworkStateSnapshot =
- buildNetworkState(TYPE_WIFI, ssid = ssid)
+ private fun buildWifiNetworkState(subscriberId: String?, ssid: String?): NetworkStateSnapshot =
+ buildNetworkState(TYPE_WIFI, subscriberId = subscriberId, ssid = ssid)
private fun buildNetworkState(
type: Int,
@@ -94,6 +100,95 @@
}
@Test
+ fun testWifiWildcardMatches() {
+ val templateWifiWildcard = buildTemplateWifiWildcard()
+
+ val identMobileImsi1 = buildNetworkIdentity(mockContext,
+ buildMobileNetworkState(TEST_IMSI1),
+ false, TelephonyManager.NETWORK_TYPE_UMTS)
+ val identWifiImsiNullSsid1 = buildNetworkIdentity(
+ mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
+ val identWifiImsi1Ssid1 = buildNetworkIdentity(
+ mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0)
+
+ templateWifiWildcard.assertDoesNotMatch(identMobileImsi1)
+ templateWifiWildcard.assertMatches(identWifiImsiNullSsid1)
+ templateWifiWildcard.assertMatches(identWifiImsi1Ssid1)
+ }
+
+ @Test
+ fun testWifiMatches() {
+ val templateWifiSsid1 = buildTemplateWifi(TEST_SSID1)
+ val templateWifiSsid1ImsiNull = buildTemplateWifi(TEST_SSID1, null)
+ val templateWifiSsid1Imsi1 = buildTemplateWifi(TEST_SSID1, TEST_IMSI1)
+ val templateWifiSsidAllImsi1 = buildTemplateWifi(WIFI_NETWORKID_ALL, TEST_IMSI1)
+
+ val identMobile1 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI1),
+ false, TelephonyManager.NETWORK_TYPE_UMTS)
+ val identWifiImsiNullSsid1 = buildNetworkIdentity(
+ mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
+ val identWifiImsi1Ssid1 = buildNetworkIdentity(
+ mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0)
+ val identWifiImsi2Ssid1 = buildNetworkIdentity(
+ mockContext, buildWifiNetworkState(TEST_IMSI2, TEST_SSID1), true, 0)
+ val identWifiImsi1Ssid2 = buildNetworkIdentity(
+ mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID2), true, 0)
+
+ // Verify that template with SSID only matches any subscriberId and specific SSID.
+ templateWifiSsid1.assertDoesNotMatch(identMobile1)
+ templateWifiSsid1.assertMatches(identWifiImsiNullSsid1)
+ templateWifiSsid1.assertMatches(identWifiImsi1Ssid1)
+ templateWifiSsid1.assertMatches(identWifiImsi2Ssid1)
+ templateWifiSsid1.assertDoesNotMatch(identWifiImsi1Ssid2)
+
+ // Verify that template with SSID1 and null imsi matches any network with
+ // SSID1 and null imsi.
+ templateWifiSsid1ImsiNull.assertDoesNotMatch(identMobile1)
+ templateWifiSsid1ImsiNull.assertMatches(identWifiImsiNullSsid1)
+ templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi1Ssid1)
+ templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi2Ssid1)
+ templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi1Ssid2)
+
+ // Verify that template with SSID1 and imsi1 matches any network with
+ // SSID1 and imsi1.
+ templateWifiSsid1Imsi1.assertDoesNotMatch(identMobile1)
+ templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsiNullSsid1)
+ templateWifiSsid1Imsi1.assertMatches(identWifiImsi1Ssid1)
+ templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsi2Ssid1)
+ templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsi1Ssid2)
+
+ // Verify that template with SSID all and imsi1 matches any network with
+ // any SSID and imsi1.
+ templateWifiSsidAllImsi1.assertDoesNotMatch(identMobile1)
+ templateWifiSsidAllImsi1.assertDoesNotMatch(identWifiImsiNullSsid1)
+ templateWifiSsidAllImsi1.assertMatches(identWifiImsi1Ssid1)
+ templateWifiSsidAllImsi1.assertDoesNotMatch(identWifiImsi2Ssid1)
+ templateWifiSsidAllImsi1.assertMatches(identWifiImsi1Ssid2)
+ }
+
+ @Test
+ fun testCarrierMatches() {
+ val templateCarrierImsi1 = buildTemplateCarrier(TEST_IMSI1)
+
+ val identMobile1 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI1),
+ false, TelephonyManager.NETWORK_TYPE_UMTS)
+ val identMobile2 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI2),
+ false, TelephonyManager.NETWORK_TYPE_UMTS)
+ val identWifiSsid1 = buildNetworkIdentity(
+ mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
+ val identCarrierWifiImsi1 = buildNetworkIdentity(
+ mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0)
+ val identCarrierWifiImsi2 = buildNetworkIdentity(
+ mockContext, buildWifiNetworkState(TEST_IMSI2, TEST_SSID1), true, 0)
+
+ templateCarrierImsi1.assertMatches(identCarrierWifiImsi1)
+ templateCarrierImsi1.assertDoesNotMatch(identCarrierWifiImsi2)
+ templateCarrierImsi1.assertDoesNotMatch(identWifiSsid1)
+ templateCarrierImsi1.assertMatches(identMobile1)
+ templateCarrierImsi1.assertDoesNotMatch(identMobile2)
+ }
+
+ @Test
fun testRatTypeGroupMatches() {
val stateMobile = buildMobileNetworkState(TEST_IMSI1)
// Build UMTS template that matches mobile identities with RAT in the same
@@ -117,7 +212,7 @@
val identImsi2 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI2),
false, TelephonyManager.NETWORK_TYPE_UMTS)
val identWifi = buildNetworkIdentity(
- mockContext, buildWifiNetworkState(TEST_SSID1), true, 0)
+ mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
// Assert that identity with the same RAT matches.
templateUmts.assertMatches(identUmts)
@@ -151,14 +246,16 @@
fun testParcelUnparcel() {
val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, null, null, METERED_ALL,
ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE,
- OEM_MANAGED_ALL)
+ OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT)
val templateWifi = NetworkTemplate(MATCH_WIFI, null, null, TEST_SSID1, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_ALL)
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_ALL,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT)
val templateOem = NetworkTemplate(MATCH_MOBILE, null, null, null, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_YES)
- assertParcelSane(templateMobile, 9)
- assertParcelSane(templateWifi, 9)
- assertParcelSane(templateOem, 9)
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_YES,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT)
+ assertParcelSane(templateMobile, 10)
+ assertParcelSane(templateWifi, 10)
+ assertParcelSane(templateOem, 10)
}
// Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with
@@ -207,15 +304,14 @@
identSsid: String? = null
) {
val oemManagedStates = arrayOf(OEM_NONE, OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
- // A null subscriberId needs a null matchSubscriberIds argument as well.
- val matchSubscriberIds = if (subscriberId == null) null else arrayOf(subscriberId)
+ val matchSubscriberIds = arrayOf(subscriberId)
val templateOemYes = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
- OEM_MANAGED_YES)
+ OEM_MANAGED_YES, SUBSCRIBER_ID_MATCH_RULE_EXACT)
val templateOemAll = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
- OEM_MANAGED_ALL)
+ OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT)
for (identityOemManagedState in oemManagedStates) {
val ident = buildNetworkIdentity(mockContext, buildNetworkState(networkType,
@@ -226,7 +322,7 @@
for (templateOemManagedState in oemManagedStates) {
val template = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
- NETWORK_TYPE_ALL, templateOemManagedState)
+ NETWORK_TYPE_ALL, templateOemManagedState, SUBSCRIBER_ID_MATCH_RULE_EXACT)
if (identityOemManagedState == templateOemManagedState) {
template.assertMatches(ident)
} else {
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index e679bb8..d966f70 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -44,9 +44,6 @@
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
@@ -57,6 +54,9 @@
import static android.net.ConnectivityManager.TYPE_PROXY;
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP;
@@ -4273,10 +4273,9 @@
waitForIdle();
}
- private void setPrivateDnsSettings(String mode, String specifier) {
- final ContentResolver cr = mServiceContext.getContentResolver();
- Settings.Global.putString(cr, ConnectivitySettingsManager.PRIVATE_DNS_MODE, mode);
- Settings.Global.putString(cr, ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER, specifier);
+ private void setPrivateDnsSettings(int mode, String specifier) {
+ ConnectivitySettingsManager.setPrivateDnsMode(mServiceContext, mode);
+ ConnectivitySettingsManager.setPrivateDnsHostname(mServiceContext, specifier);
mService.updatePrivateDnsSettings();
waitForIdle();
}
@@ -10479,7 +10478,7 @@
assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_VALIDATED));
assertTrue(mRequests.get(1).isRequest());
assertTrue(mRequests.get(1).hasCapability(NET_CAPABILITY_OEM_PAID));
- assertTrue(mRequests.get(2).isRequest());
+ assertEquals(NetworkRequest.Type.TRACK_DEFAULT, mRequests.get(2).type);
assertTrue(mService.getDefaultRequest().networkCapabilities.equalsNetCapabilities(
mRequests.get(2).networkCapabilities));
}
@@ -11693,10 +11692,12 @@
mServiceContext, "internetFactory", internetFilter, mCsHandlerThread);
internetFactory.setScoreFilter(40);
internetFactory.register();
- // Default internet request & 3rd (fallback) request in OEM_PAID NRI. The unmetered request
- // is never sent to factories (it's a LISTEN, not requestable) and the OEM_PAID request
- // doesn't match the internetFactory filter.
- internetFactory.expectRequestAdds(2);
+ // Default internet request only. The unmetered request is never sent to factories (it's a
+ // LISTEN, not requestable). The 3rd (fallback) request in OEM_PAID NRI is TRACK_DEFAULT
+ // which is also not sent to factories. Finally, the OEM_PAID request doesn't match the
+ // internetFactory filter.
+ internetFactory.expectRequestAdds(1);
+ internetFactory.assertRequestCountEquals(1);
NetworkCapabilities oemPaidFilter = new NetworkCapabilities()
.addCapability(NET_CAPABILITY_INTERNET)
@@ -11719,7 +11720,7 @@
expectNoRequestChanged(oemPaidFactory);
oemPaidFactory.assertRequestCountEquals(1);
// The internet factory however is outscored, and should lose its requests.
- internetFactory.expectRequestRemoves(2);
+ internetFactory.expectRequestRemove();
internetFactory.assertRequestCountEquals(0);
final NetworkCapabilities oemPaidNc = new NetworkCapabilities();
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index 692c50f..0ffeec9 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -16,10 +16,10 @@
package com.android.server.connectivity;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE;
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER;
import static android.net.NetworkCapabilities.MAX_TRANSPORT;
import static android.net.NetworkCapabilities.MIN_TRANSPORT;
@@ -44,6 +44,7 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.net.ConnectivitySettingsManager;
import android.net.IDnsResolver;
import android.net.IpPrefix;
import android.net.LinkAddress;
@@ -187,9 +188,8 @@
lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
TEST_IFACENAME));
- Settings.Global.putString(mContentResolver,
- PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
- Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com");
+ ConnectivitySettingsManager.setPrivateDnsMode(mCtx, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+ ConnectivitySettingsManager.setPrivateDnsHostname(mCtx, "strictmode.com");
mDnsManager.updatePrivateDns(new Network(TEST_NETID),
new PrivateDnsConfig("strictmode.com", new InetAddress[] {
InetAddress.parseNumericAddress("6.6.6.6"),
@@ -294,7 +294,7 @@
assertNull(lp.getPrivateDnsServerName());
// Turn private DNS mode off
- Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OFF);
+ ConnectivitySettingsManager.setPrivateDnsMode(mCtx, PRIVATE_DNS_MODE_OFF);
mDnsManager.updatePrivateDns(new Network(TEST_NETID),
mDnsManager.getPrivateDnsConfig());
mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
@@ -318,16 +318,15 @@
assertEquals(new InetAddress[0], cfgAuto.ips);
// Pretend a gservices push sets the default to "off".
- Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "off");
+ ConnectivitySettingsManager.setPrivateDnsDefaultMode(mCtx, PRIVATE_DNS_MODE_OFF);
final PrivateDnsConfig cfgOff = DnsManager.getPrivateDnsConfig(mCtx);
assertFalse(cfgOff.useTls);
assertEquals("", cfgOff.hostname);
assertEquals(new InetAddress[0], cfgOff.ips);
// Strict mode still works.
- Settings.Global.putString(
- mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
- Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com");
+ ConnectivitySettingsManager.setPrivateDnsMode(mCtx, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+ ConnectivitySettingsManager.setPrivateDnsHostname(mCtx, "strictmode.com");
final PrivateDnsConfig cfgStrict = DnsManager.getPrivateDnsConfig(mCtx);
assertTrue(cfgStrict.useTls);
assertEquals("strictmode.com", cfgStrict.hostname);
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 42441c2..fd374bc 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -45,6 +45,7 @@
import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
import static android.net.NetworkTemplate.OEM_MANAGED_NO;
import static android.net.NetworkTemplate.OEM_MANAGED_YES;
+import static android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
import static android.net.NetworkTemplate.buildTemplateWifi;
@@ -669,24 +670,28 @@
public void testMobileStatsOemManaged() throws Exception {
final NetworkTemplate templateOemPaid = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
/*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PAID);
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PAID,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT);
final NetworkTemplate templateOemPrivate = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
/*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PRIVATE);
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PRIVATE,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT);
final NetworkTemplate templateOemAll = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
/*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
- OEM_PAID | OEM_PRIVATE);
+ OEM_PAID | OEM_PRIVATE, SUBSCRIBER_ID_MATCH_RULE_EXACT);
final NetworkTemplate templateOemYes = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
/*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_YES);
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_YES,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT);
final NetworkTemplate templateOemNone = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
/*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_NO);
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_NO,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT);
// OEM_PAID network comes online.
NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index 0d3fd3f..7cfd275 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -22,7 +22,7 @@
import static org.junit.Assert.fail;
import android.net.NetworkCapabilities;
-import android.net.TunnelConnectionParams;
+import android.net.ipsec.ike.IkeTunnelConnectionParams;
import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtilsTest;
import androidx.test.filters.SmallTest;
@@ -60,7 +60,7 @@
};
public static final int MAX_MTU = 1360;
- public static final TunnelConnectionParams TUNNEL_CONNECTION_PARAMS =
+ public static final IkeTunnelConnectionParams TUNNEL_CONNECTION_PARAMS =
TunnelConnectionParamsUtilsTest.buildTestParams();
public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-";
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 530e636..90ee738 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -51,7 +51,6 @@
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.ipsec.ike.ChildSaProposal;
-import android.net.ipsec.ike.IkeTunnelConnectionParams;
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeInternalException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
@@ -181,7 +180,7 @@
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
final List<ChildSaProposal> saProposals =
- ((IkeTunnelConnectionParams) mConfig.getTunnelConnectionParams())
+ mConfig.getTunnelConnectionParams()
.getTunnelModeChildSessionParams()
.getSaProposals();
final int expectedMtu =