Merge "UserController/Manager loglines"
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 144536e..646a027 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -324,6 +324,7 @@
private final NetworkRequest networkRequest;
private final long networkDownloadBytes;
private final long networkUploadBytes;
+ private final long minimumNetworkChunkBytes;
private final long minLatencyMillis;
private final long maxExecutionDelayMillis;
private final boolean isPeriodic;
@@ -515,6 +516,17 @@
}
/**
+ * Return the smallest piece of data that cannot be easily paused and resumed, in bytes.
+ *
+ * @return Smallest piece of data that cannot be easily paused and resumed, or
+ * {@link #NETWORK_BYTES_UNKNOWN} when unknown.
+ * @see Builder#setMinimumNetworkChunkBytes(long)
+ */
+ public @BytesLong long getMinimumNetworkChunkBytes() {
+ return minimumNetworkChunkBytes;
+ }
+
+ /**
* Set for a job that does not recur periodically, to specify a delay after which the job
* will be eligible for execution. This value is not set if the job recurs periodically.
* @see JobInfo.Builder#setMinimumLatency(long)
@@ -679,6 +691,9 @@
if (networkUploadBytes != j.networkUploadBytes) {
return false;
}
+ if (minimumNetworkChunkBytes != j.minimumNetworkChunkBytes) {
+ return false;
+ }
if (minLatencyMillis != j.minLatencyMillis) {
return false;
}
@@ -741,6 +756,7 @@
}
hashCode = 31 * hashCode + Long.hashCode(networkDownloadBytes);
hashCode = 31 * hashCode + Long.hashCode(networkUploadBytes);
+ hashCode = 31 * hashCode + Long.hashCode(minimumNetworkChunkBytes);
hashCode = 31 * hashCode + Long.hashCode(minLatencyMillis);
hashCode = 31 * hashCode + Long.hashCode(maxExecutionDelayMillis);
hashCode = 31 * hashCode + Boolean.hashCode(isPeriodic);
@@ -777,6 +793,7 @@
}
networkDownloadBytes = in.readLong();
networkUploadBytes = in.readLong();
+ minimumNetworkChunkBytes = in.readLong();
minLatencyMillis = in.readLong();
maxExecutionDelayMillis = in.readLong();
isPeriodic = in.readInt() == 1;
@@ -807,6 +824,7 @@
networkRequest = b.mNetworkRequest;
networkDownloadBytes = b.mNetworkDownloadBytes;
networkUploadBytes = b.mNetworkUploadBytes;
+ minimumNetworkChunkBytes = b.mMinimumNetworkChunkBytes;
minLatencyMillis = b.mMinLatencyMillis;
maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
isPeriodic = b.mIsPeriodic;
@@ -851,6 +869,7 @@
}
out.writeLong(networkDownloadBytes);
out.writeLong(networkUploadBytes);
+ out.writeLong(minimumNetworkChunkBytes);
out.writeLong(minLatencyMillis);
out.writeLong(maxExecutionDelayMillis);
out.writeInt(isPeriodic ? 1 : 0);
@@ -986,6 +1005,7 @@
private NetworkRequest mNetworkRequest;
private long mNetworkDownloadBytes = NETWORK_BYTES_UNKNOWN;
private long mNetworkUploadBytes = NETWORK_BYTES_UNKNOWN;
+ private long mMinimumNetworkChunkBytes = NETWORK_BYTES_UNKNOWN;
private ArrayList<TriggerContentUri> mTriggerContentUris;
private long mTriggerContentUpdateDelay = -1;
private long mTriggerContentMaxDelay = -1;
@@ -1038,6 +1058,7 @@
mNetworkRequest = job.getRequiredNetwork();
mNetworkDownloadBytes = job.getEstimatedNetworkDownloadBytes();
mNetworkUploadBytes = job.getEstimatedNetworkUploadBytes();
+ mMinimumNetworkChunkBytes = job.getMinimumNetworkChunkBytes();
mTriggerContentUris = job.getTriggerContentUris() != null
? new ArrayList<>(Arrays.asList(job.getTriggerContentUris())) : null;
mTriggerContentUpdateDelay = job.getTriggerContentUpdateDelay();
@@ -1256,6 +1277,39 @@
}
/**
+ * Set the minimum size of non-resumable network traffic this job requires, in bytes. When
+ * the upload or download can be easily paused and resumed, use this to set the smallest
+ * size that must be transmitted between start and stop events to be considered successful.
+ * If the transfer cannot be paused and resumed, then this should be the sum of the values
+ * provided to {@link JobInfo.Builder#setEstimatedNetworkBytes(long, long)}.
+ *
+ * <p>
+ * Apps are encouraged to provide values that are as accurate as possible since JobScheduler
+ * will try to run the job at a time when at least the minimum chunk can be transmitted to
+ * reduce the amount of repetitive data that's transferred. Jobs that cannot provide
+ * reasonable estimates should use the sentinel value {@link JobInfo#NETWORK_BYTES_UNKNOWN}.
+ *
+ * <p>
+ * The values provided here only reflect the minimum non-resumable traffic that will be
+ * performed by the base job; if you're using {@link JobWorkItem} then
+ * you also need to define the network traffic used by each work item
+ * when constructing them.
+ *
+ * @param chunkSizeBytes The smallest piece of data that cannot be easily paused and
+ * resumed, in bytes.
+ * @see JobInfo#getMinimumNetworkChunkBytes()
+ * @see JobWorkItem#JobWorkItem(android.content.Intent, long, long, long)
+ */
+ @NonNull
+ public Builder setMinimumNetworkChunkBytes(@BytesLong long chunkSizeBytes) {
+ if (chunkSizeBytes != NETWORK_BYTES_UNKNOWN && chunkSizeBytes <= 0) {
+ throw new IllegalArgumentException("Minimum chunk size must be positive");
+ }
+ mMinimumNetworkChunkBytes = chunkSizeBytes;
+ return this;
+ }
+
+ /**
* Specify that to run this job, the device must be charging (or be a
* non-battery-powered device connected to permanent power, such as Android TV
* devices). This defaults to {@code false}.
@@ -1647,12 +1701,29 @@
/**
* @hide
*/
- public void enforceValidity() {
- // Check that network estimates require network type
- if ((networkDownloadBytes > 0 || networkUploadBytes > 0) && networkRequest == null) {
+ public final void enforceValidity() {
+ // Check that network estimates require network type and are reasonable values.
+ if ((networkDownloadBytes > 0 || networkUploadBytes > 0 || minimumNetworkChunkBytes > 0)
+ && networkRequest == null) {
throw new IllegalArgumentException(
"Can't provide estimated network usage without requiring a network");
}
+ final long estimatedTransfer;
+ if (networkUploadBytes == NETWORK_BYTES_UNKNOWN) {
+ estimatedTransfer = networkDownloadBytes;
+ } else {
+ estimatedTransfer = networkUploadBytes
+ + (networkDownloadBytes == NETWORK_BYTES_UNKNOWN ? 0 : networkDownloadBytes);
+ }
+ if (minimumNetworkChunkBytes != NETWORK_BYTES_UNKNOWN
+ && estimatedTransfer != NETWORK_BYTES_UNKNOWN
+ && minimumNetworkChunkBytes > estimatedTransfer) {
+ throw new IllegalArgumentException(
+ "Minimum chunk size can't be greater than estimated network usage");
+ }
+ if (minimumNetworkChunkBytes != NETWORK_BYTES_UNKNOWN && minimumNetworkChunkBytes <= 0) {
+ throw new IllegalArgumentException("Minimum chunk size must be positive");
+ }
// Check that a deadline was not set on a periodic job.
if (isPeriodic) {
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java b/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java
index 0c45cbf..372f9fa 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java
@@ -19,6 +19,7 @@
import static android.app.job.JobInfo.NETWORK_BYTES_UNKNOWN;
import android.annotation.BytesLong;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
import android.os.Build;
@@ -33,8 +34,9 @@
final public class JobWorkItem implements Parcelable {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final Intent mIntent;
- final long mNetworkDownloadBytes;
- final long mNetworkUploadBytes;
+ private final long mNetworkDownloadBytes;
+ private final long mNetworkUploadBytes;
+ private final long mMinimumChunkBytes;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
int mDeliveryCount;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -49,9 +51,7 @@
* @param intent The general Intent describing this work.
*/
public JobWorkItem(Intent intent) {
- mIntent = intent;
- mNetworkDownloadBytes = NETWORK_BYTES_UNKNOWN;
- mNetworkUploadBytes = NETWORK_BYTES_UNKNOWN;
+ this(intent, NETWORK_BYTES_UNKNOWN, NETWORK_BYTES_UNKNOWN);
}
/**
@@ -68,9 +68,45 @@
* uploaded by this job work item, in bytes.
*/
public JobWorkItem(Intent intent, @BytesLong long downloadBytes, @BytesLong long uploadBytes) {
+ this(intent, downloadBytes, uploadBytes, NETWORK_BYTES_UNKNOWN);
+ }
+
+ /**
+ * Create a new piece of work, which can be submitted to
+ * {@link JobScheduler#enqueue JobScheduler.enqueue}.
+ * <p>
+ * See {@link JobInfo.Builder#setEstimatedNetworkBytes(long, long)} for
+ * details about how to estimate network traffic.
+ *
+ * @param intent The general Intent describing this work.
+ * @param downloadBytes The estimated size of network traffic that will be
+ * downloaded by this job work item, in bytes.
+ * @param uploadBytes The estimated size of network traffic that will be
+ * uploaded by this job work item, in bytes.
+ * @param minimumChunkBytes The smallest piece of data that cannot be easily paused and
+ * resumed, in bytes.
+ */
+ public JobWorkItem(@Nullable Intent intent, @BytesLong long downloadBytes,
+ @BytesLong long uploadBytes, @BytesLong long minimumChunkBytes) {
+ if (minimumChunkBytes != NETWORK_BYTES_UNKNOWN && minimumChunkBytes <= 0) {
+ throw new IllegalArgumentException("Minimum chunk size must be positive");
+ }
+ final long estimatedTransfer;
+ if (uploadBytes == NETWORK_BYTES_UNKNOWN) {
+ estimatedTransfer = downloadBytes;
+ } else {
+ estimatedTransfer = uploadBytes
+ + (downloadBytes == NETWORK_BYTES_UNKNOWN ? 0 : downloadBytes);
+ }
+ if (minimumChunkBytes != NETWORK_BYTES_UNKNOWN && estimatedTransfer != NETWORK_BYTES_UNKNOWN
+ && minimumChunkBytes > estimatedTransfer) {
+ throw new IllegalArgumentException(
+ "Minimum chunk size can't be greater than estimated network usage");
+ }
mIntent = intent;
mNetworkDownloadBytes = downloadBytes;
mNetworkUploadBytes = uploadBytes;
+ mMinimumChunkBytes = minimumChunkBytes;
}
/**
@@ -103,6 +139,16 @@
}
/**
+ * Return the smallest piece of data that cannot be easily paused and resumed, in bytes.
+ *
+ * @return Smallest piece of data that cannot be easily paused and resumed, or
+ * {@link JobInfo#NETWORK_BYTES_UNKNOWN} when unknown.
+ */
+ public @BytesLong long getMinimumNetworkChunkBytes() {
+ return mMinimumChunkBytes;
+ }
+
+ /**
* Return the count of the number of times this work item has been delivered
* to the job. The value will be > 1 if it has been redelivered because the job
* was stopped or crashed while it had previously been delivered but before the
@@ -161,6 +207,10 @@
sb.append(" uploadBytes=");
sb.append(mNetworkUploadBytes);
}
+ if (mMinimumChunkBytes != NETWORK_BYTES_UNKNOWN) {
+ sb.append(" minimumChunkBytes=");
+ sb.append(mMinimumChunkBytes);
+ }
if (mDeliveryCount != 0) {
sb.append(" dcount=");
sb.append(mDeliveryCount);
@@ -169,6 +219,28 @@
return sb.toString();
}
+ /**
+ * @hide
+ */
+ public void enforceValidity() {
+ final long estimatedTransfer;
+ if (mNetworkUploadBytes == NETWORK_BYTES_UNKNOWN) {
+ estimatedTransfer = mNetworkDownloadBytes;
+ } else {
+ estimatedTransfer = mNetworkUploadBytes
+ + (mNetworkDownloadBytes == NETWORK_BYTES_UNKNOWN ? 0 : mNetworkDownloadBytes);
+ }
+ if (mMinimumChunkBytes != NETWORK_BYTES_UNKNOWN
+ && estimatedTransfer != NETWORK_BYTES_UNKNOWN
+ && mMinimumChunkBytes > estimatedTransfer) {
+ throw new IllegalArgumentException(
+ "Minimum chunk size can't be greater than estimated network usage");
+ }
+ if (mMinimumChunkBytes != NETWORK_BYTES_UNKNOWN && mMinimumChunkBytes <= 0) {
+ throw new IllegalArgumentException("Minimum chunk size must be positive");
+ }
+ }
+
public int describeContents() {
return 0;
}
@@ -182,6 +254,7 @@
}
out.writeLong(mNetworkDownloadBytes);
out.writeLong(mNetworkUploadBytes);
+ out.writeLong(mMinimumChunkBytes);
out.writeInt(mDeliveryCount);
out.writeInt(mWorkId);
}
@@ -206,6 +279,7 @@
}
mNetworkDownloadBytes = in.readLong();
mNetworkUploadBytes = in.readLong();
+ mMinimumChunkBytes = in.readLong();
mDeliveryCount = in.readInt();
mWorkId = in.readInt();
}
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 ed80ddb..9f52954 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -256,6 +256,7 @@
AlarmHandler mHandler;
AppWakeupHistory mAppWakeupHistory;
AppWakeupHistory mAllowWhileIdleHistory;
+ AppWakeupHistory mAllowWhileIdleCompatHistory;
private final SparseLongArray mLastPriorityAlarmDispatch = new SparseLongArray();
private final SparseArray<RingBuffer<RemovedAlarm>> mRemovalHistory = new SparseArray<>();
ClockReceiver mClockReceiver;
@@ -1633,6 +1634,7 @@
mAppWakeupHistory = new AppWakeupHistory(Constants.DEFAULT_APP_STANDBY_WINDOW);
mAllowWhileIdleHistory = new AppWakeupHistory(INTERVAL_HOUR);
+ mAllowWhileIdleCompatHistory = new AppWakeupHistory(INTERVAL_HOUR);
mNextWakeup = mNextNonWakeup = 0;
@@ -2142,20 +2144,23 @@
final int userId = UserHandle.getUserId(alarm.creatorUid);
final int quota;
final long window;
+ final AppWakeupHistory history;
if ((alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0) {
quota = mConstants.ALLOW_WHILE_IDLE_QUOTA;
window = mConstants.ALLOW_WHILE_IDLE_WINDOW;
+ history = mAllowWhileIdleHistory;
} else {
quota = mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
window = mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+ history = mAllowWhileIdleCompatHistory;
}
- final int dispatchesInWindow = mAllowWhileIdleHistory.getTotalWakeupsInWindow(
+ final int dispatchesInHistory = history.getTotalWakeupsInWindow(
alarm.sourcePackage, userId);
- if (dispatchesInWindow < quota) {
+ if (dispatchesInHistory < quota) {
// fine to go out immediately.
batterySaverPolicyElapsed = nowElapsed;
} else {
- batterySaverPolicyElapsed = mAllowWhileIdleHistory.getNthLastWakeupForPackage(
+ batterySaverPolicyElapsed = history.getNthLastWakeupForPackage(
alarm.sourcePackage, userId, quota) + window;
}
} else if ((alarm.flags & FLAG_PRIORITIZE) != 0) {
@@ -2201,20 +2206,23 @@
final int userId = UserHandle.getUserId(alarm.creatorUid);
final int quota;
final long window;
+ final AppWakeupHistory history;
if ((alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0) {
quota = mConstants.ALLOW_WHILE_IDLE_QUOTA;
window = mConstants.ALLOW_WHILE_IDLE_WINDOW;
+ history = mAllowWhileIdleHistory;
} else {
quota = mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
window = mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+ history = mAllowWhileIdleCompatHistory;
}
- final int dispatchesInWindow = mAllowWhileIdleHistory.getTotalWakeupsInWindow(
+ final int dispatchesInHistory = history.getTotalWakeupsInWindow(
alarm.sourcePackage, userId);
- if (dispatchesInWindow < quota) {
+ if (dispatchesInHistory < quota) {
// fine to go out immediately.
deviceIdlePolicyTime = nowElapsed;
} else {
- final long whenInQuota = mAllowWhileIdleHistory.getNthLastWakeupForPackage(
+ final long whenInQuota = history.getNthLastWakeupForPackage(
alarm.sourcePackage, userId, quota) + window;
deviceIdlePolicyTime = Math.min(whenInQuota, mPendingIdleUntil.getWhenElapsed());
}
@@ -2502,6 +2510,7 @@
Binder.getCallingPid(), callingUid, "AlarmManager.setPrioritized");
// The API doesn't allow using both together.
flags &= ~FLAG_ALLOW_WHILE_IDLE;
+ // Prioritized alarms don't need any extra permission to be exact.
} else if (exact || allowWhileIdle) {
final boolean needsPermission;
boolean lowerQuota;
@@ -2992,6 +3001,10 @@
mAllowWhileIdleHistory.dump(pw, nowELAPSED);
pw.println();
+ pw.println("Allow while idle compat history:");
+ mAllowWhileIdleCompatHistory.dump(pw, nowELAPSED);
+ pw.println();
+
if (mLastPriorityAlarmDispatch.size() > 0) {
pw.println("Last priority alarm dispatches:");
pw.increaseIndent();
@@ -4553,6 +4566,7 @@
removeUserLocked(userHandle);
mAppWakeupHistory.removeForUser(userHandle);
mAllowWhileIdleHistory.removeForUser(userHandle);
+ mAllowWhileIdleCompatHistory.removeForUser(userHandle);
}
return;
case Intent.ACTION_UID_REMOVED:
@@ -4588,6 +4602,8 @@
// package-removed and package-restarted case
mAppWakeupHistory.removeForPackage(pkg, UserHandle.getUserId(uid));
mAllowWhileIdleHistory.removeForPackage(pkg, UserHandle.getUserId(uid));
+ mAllowWhileIdleCompatHistory.removeForPackage(pkg,
+ UserHandle.getUserId(uid));
removeLocked(uid, REMOVE_REASON_UNDEFINED);
} else {
// external-applications-unavailable case
@@ -4965,7 +4981,10 @@
if (isAllowedWhileIdleRestricted(alarm)) {
// Record the last time this uid handled an ALLOW_WHILE_IDLE alarm while the
// device was in doze or battery saver.
- mAllowWhileIdleHistory.recordAlarmForPackage(alarm.sourcePackage,
+ final AppWakeupHistory history = ((alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0)
+ ? mAllowWhileIdleHistory
+ : mAllowWhileIdleCompatHistory;
+ history.recordAlarmForPackage(alarm.sourcePackage,
UserHandle.getUserId(alarm.creatorUid), nowELAPSED);
mAlarmStore.updateAlarmDeliveries(a -> {
if (a.creatorUid != alarm.creatorUid || !isAllowedWhileIdleRestricted(a)) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 72d8e72..f3b2a96 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -2806,6 +2806,7 @@
throw new NullPointerException("work is null");
}
+ work.enforceValidity();
validateJobFlags(job, uid);
final long ident = Binder.clearCallingIdentity();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 41ff9c8..9a25772 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -549,6 +549,47 @@
*/
private boolean isInsane(JobStatus jobStatus, Network network,
NetworkCapabilities capabilities, Constants constants) {
+ // Use the maximum possible time since it gives us an upper bound, even though the job
+ // could end up stopping earlier.
+ final long maxJobExecutionTimeMs = mService.getMaxJobExecutionTimeMs(jobStatus);
+
+ final long minimumChunkBytes = jobStatus.getMinimumNetworkChunkBytes();
+ if (minimumChunkBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
+ final long bandwidthDown = capabilities.getLinkDownstreamBandwidthKbps();
+ // If we don't know the bandwidth, all we can do is hope the job finishes the minimum
+ // chunk in time.
+ if (bandwidthDown > 0) {
+ // Divide by 8 to convert bits to bytes.
+ final long estimatedMillis = ((minimumChunkBytes * DateUtils.SECOND_IN_MILLIS)
+ / (DataUnit.KIBIBYTES.toBytes(bandwidthDown) / 8));
+ if (estimatedMillis > maxJobExecutionTimeMs) {
+ // If we'd never finish the minimum chunk before the timeout, we'd be insane!
+ Slog.w(TAG, "Minimum chunk " + minimumChunkBytes + " bytes over "
+ + bandwidthDown + " kbps network would take "
+ + estimatedMillis + "ms and job has "
+ + maxJobExecutionTimeMs + "ms to run; that's insane!");
+ return true;
+ }
+ }
+ final long bandwidthUp = capabilities.getLinkUpstreamBandwidthKbps();
+ // If we don't know the bandwidth, all we can do is hope the job finishes in time.
+ if (bandwidthUp > 0) {
+ // Divide by 8 to convert bits to bytes.
+ final long estimatedMillis = ((minimumChunkBytes * DateUtils.SECOND_IN_MILLIS)
+ / (DataUnit.KIBIBYTES.toBytes(bandwidthUp) / 8));
+ if (estimatedMillis > maxJobExecutionTimeMs) {
+ // If we'd never finish the minimum chunk before the timeout, we'd be insane!
+ Slog.w(TAG, "Minimum chunk " + minimumChunkBytes + " bytes over " + bandwidthUp
+ + " kbps network would take " + estimatedMillis + "ms and job has "
+ + maxJobExecutionTimeMs + "ms to run; that's insane!");
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Minimum chunk size isn't defined. Check using the estimated upload/download sizes.
+
if (capabilities.hasCapability(NET_CAPABILITY_NOT_METERED)
&& mChargingTracker.isCharging()) {
// We're charging and on an unmetered network. We don't have to be as conservative about
@@ -557,9 +598,6 @@
return false;
}
- // Use the maximum possible time since it gives us an upper bound, even though the job
- // could end up stopping earlier.
- final long maxJobExecutionTimeMs = mService.getMaxJobExecutionTimeMs(jobStatus);
final long downloadBytes = jobStatus.getEstimatedNetworkDownloadBytes();
if (downloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 95eb220..fda57f7 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -391,6 +391,7 @@
private long mTotalNetworkDownloadBytes = JobInfo.NETWORK_BYTES_UNKNOWN;
private long mTotalNetworkUploadBytes = JobInfo.NETWORK_BYTES_UNKNOWN;
+ private long mMinimumNetworkChunkBytes = JobInfo.NETWORK_BYTES_UNKNOWN;
/////// Booleans that track if a job is ready to run. They should be updated whenever dependent
/////// states change.
@@ -531,7 +532,7 @@
mInternalFlags = internalFlags;
- updateEstimatedNetworkBytesLocked();
+ updateNetworkBytesLocked();
if (job.getRequiredNetwork() != null) {
// Later, when we check if a given network satisfies the required
@@ -664,7 +665,7 @@
sourcePackageName, sourceUserId, toShortString()));
}
pendingWork.add(work);
- updateEstimatedNetworkBytesLocked();
+ updateNetworkBytesLocked();
}
public JobWorkItem dequeueWorkLocked() {
@@ -677,7 +678,7 @@
executingWork.add(work);
work.bumpDeliveryCount();
}
- updateEstimatedNetworkBytesLocked();
+ updateNetworkBytesLocked();
return work;
}
return null;
@@ -736,7 +737,7 @@
pendingWork = null;
executingWork = null;
incomingJob.nextPendingWorkId = nextPendingWorkId;
- incomingJob.updateEstimatedNetworkBytesLocked();
+ incomingJob.updateNetworkBytesLocked();
} else {
// We are completely stopping the job... need to clean up work.
ungrantWorkList(pendingWork);
@@ -744,7 +745,7 @@
ungrantWorkList(executingWork);
executingWork = null;
}
- updateEstimatedNetworkBytesLocked();
+ updateNetworkBytesLocked();
}
public void prepareLocked() {
@@ -944,9 +945,10 @@
}
}
- private void updateEstimatedNetworkBytesLocked() {
+ private void updateNetworkBytesLocked() {
mTotalNetworkDownloadBytes = job.getEstimatedNetworkDownloadBytes();
mTotalNetworkUploadBytes = job.getEstimatedNetworkUploadBytes();
+ mMinimumNetworkChunkBytes = job.getMinimumNetworkChunkBytes();
if (pendingWork != null) {
for (int i = 0; i < pendingWork.size(); i++) {
@@ -968,6 +970,12 @@
mTotalNetworkUploadBytes += uploadBytes;
}
}
+ final long chunkBytes = pendingWork.get(i).getMinimumNetworkChunkBytes();
+ if (mMinimumNetworkChunkBytes == JobInfo.NETWORK_BYTES_UNKNOWN) {
+ mMinimumNetworkChunkBytes = chunkBytes;
+ } else if (chunkBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
+ mMinimumNetworkChunkBytes = Math.min(mMinimumNetworkChunkBytes, chunkBytes);
+ }
}
}
}
@@ -980,6 +988,10 @@
return mTotalNetworkUploadBytes;
}
+ public long getMinimumNetworkChunkBytes() {
+ return mMinimumNetworkChunkBytes;
+ }
+
/** Does this job have any sort of networking constraint? */
public boolean hasConnectivityConstraint() {
// No need to check mDynamicConstraints since connectivity will only be in that list if
@@ -1942,6 +1954,10 @@
pw.print("Network upload bytes: ");
pw.println(mTotalNetworkUploadBytes);
}
+ if (mMinimumNetworkChunkBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
+ pw.print("Minimum network chunk bytes: ");
+ pw.println(mMinimumNetworkChunkBytes);
+ }
if (job.getMinLatencyMillis() != 0) {
pw.print("Minimum latency: ");
TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/restrictions/JobRestriction.java b/apex/jobscheduler/service/java/com/android/server/job/restrictions/JobRestriction.java
index 20df3ea..5193179 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/restrictions/JobRestriction.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/restrictions/JobRestriction.java
@@ -66,7 +66,8 @@
public abstract void dumpConstants(IndentingPrintWriter pw);
/** Dump any internal constants the Restriction may have. */
- public abstract void dumpConstants(ProtoOutputStream proto);
+ public void dumpConstants(ProtoOutputStream proto) {
+ }
/** @return reason code for the Restriction. */
@JobParameters.StopReason
diff --git a/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java b/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java
index 3069db3..5695a94 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java
@@ -20,16 +20,21 @@
import android.os.PowerManager;
import android.os.PowerManager.OnThermalStatusChangedListener;
import android.util.IndentingPrintWriter;
-import android.util.proto.ProtoOutputStream;
import com.android.server.job.JobSchedulerService;
-import com.android.server.job.JobSchedulerServiceDumpProto;
import com.android.server.job.controllers.JobStatus;
public class ThermalStatusRestriction extends JobRestriction {
private static final String TAG = "ThermalStatusRestriction";
- private volatile boolean mIsThermalRestricted = false;
+ /** The threshold at which we start restricting non-EJ jobs. */
+ private static final int REGULAR_JOB_THRESHOLD = PowerManager.THERMAL_STATUS_SEVERE;
+ /** The lowest threshold at which we start restricting jobs. */
+ private static final int LOWER_THRESHOLD = REGULAR_JOB_THRESHOLD;
+ /** The threshold at which we start restricting ALL jobs. */
+ private static final int UPPER_THRESHOLD = PowerManager.THERMAL_STATUS_CRITICAL;
+
+ private volatile int mThermalStatus = PowerManager.THERMAL_STATUS_NONE;
private PowerManager mPowerManager;
@@ -47,29 +52,46 @@
public void onThermalStatusChanged(int status) {
// This is called on the main thread. Do not do any slow operations in it.
// mService.onControllerStateChanged() will just post a message, which is okay.
- final boolean shouldBeActive = status >= PowerManager.THERMAL_STATUS_SEVERE;
- if (mIsThermalRestricted == shouldBeActive) {
- return;
+
+ // There are three buckets:
+ // 1. Below the lower threshold (we don't care about changes within this bucket)
+ // 2. Between the lower and upper thresholds.
+ // -> We care about transitions across buckets
+ // -> We care about transitions within the middle bucket
+ // 3. Upper the upper threshold (we don't care about changes within this bucket)
+ final boolean significantChange =
+ // Handle transitions within and into the bucket we care about (thus
+ // causing us to change our restrictions).
+ (status >= LOWER_THRESHOLD && status <= UPPER_THRESHOLD)
+ // Take care of transitions from the 2nd or 3rd bucket to the 1st
+ // bucket (thus exiting any restrictions we started enforcing).
+ || (mThermalStatus >= LOWER_THRESHOLD && status < LOWER_THRESHOLD)
+ // Take care of transitions from the 1st or 2nd bucket to the 3rd
+ // bucket (thus resulting in us beginning to enforce the tightest
+ // restrictions).
+ || (mThermalStatus < UPPER_THRESHOLD && status > UPPER_THRESHOLD);
+ mThermalStatus = status;
+ if (significantChange) {
+ mService.onControllerStateChanged();
}
- mIsThermalRestricted = shouldBeActive;
- mService.onControllerStateChanged();
}
});
}
@Override
public boolean isJobRestricted(JobStatus job) {
- return mIsThermalRestricted && job.hasConnectivityConstraint();
+ if (mThermalStatus >= UPPER_THRESHOLD) {
+ return true;
+ }
+ if (mThermalStatus >= REGULAR_JOB_THRESHOLD) {
+ return !job.shouldTreatAsExpeditedJob();
+ }
+ return false;
}
@Override
public void dumpConstants(IndentingPrintWriter pw) {
- pw.print("In thermal throttling?: ");
- pw.println(mIsThermalRestricted);
- }
-
- @Override
- public void dumpConstants(ProtoOutputStream proto) {
- proto.write(JobSchedulerServiceDumpProto.IN_THERMAL, mIsThermalRestricted);
+ pw.print("Thermal status: ");
+ pw.println(mThermalStatus);
}
}
diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp
index b2b66c2..3534624 100644
--- a/cmds/bootanimation/Android.bp
+++ b/cmds/bootanimation/Android.bp
@@ -71,7 +71,7 @@
"libui",
"libjnigraphics",
"libEGL",
- "libGLESv1_CM",
+ "libGLESv2",
"libgui",
],
}
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 3109c5c..25b7f24 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -52,9 +52,8 @@
#include <gui/DisplayEventReceiver.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
-
-#include <GLES/gl.h>
-#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
#include <EGL/eglext.h>
#include "BootAnimation.h"
@@ -108,6 +107,53 @@
static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays";
static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1;
static constexpr size_t TEXT_POS_LEN_MAX = 16;
+static const char U_TEXTURE[] = "uTexture";
+static const char U_FADE[] = "uFade";
+static const char U_CROP_AREA[] = "uCropArea";
+static const char A_UV[] = "aUv";
+static const char A_POSITION[] = "aPosition";
+static const char VERTEX_SHADER_SOURCE[] = R"(
+ attribute vec4 aPosition;
+ attribute vec2 aUv;
+ varying vec2 vUv;
+ void main() {
+ gl_Position = aPosition;
+ vUv = aUv;
+ })";
+static const char IMAGE_FRAG_SHADER_SOURCE[] = R"(
+ uniform sampler2D uTexture;
+ uniform float uFade;
+ varying vec2 vUv;
+ void main() {
+ vec4 color = texture2D(uTexture, vUv);
+ gl_FragColor = vec4(color.x, color.y, color.z, 1.0 - uFade);
+ })";
+static const char TEXT_FRAG_SHADER_SOURCE[] = R"(
+ uniform sampler2D uTexture;
+ uniform vec4 uCropArea;
+ varying vec2 vUv;
+ void main() {
+ vec2 uv = vec2(mix(uCropArea.x, uCropArea.z, vUv.x),
+ mix(uCropArea.y, uCropArea.w, vUv.y));
+ gl_FragColor = texture2D(uTexture, uv);
+ })";
+
+static GLfloat quadPositions[] = {
+ -0.5f, -0.5f,
+ +0.5f, -0.5f,
+ +0.5f, +0.5f,
+ +0.5f, +0.5f,
+ -0.5f, +0.5f,
+ -0.5f, -0.5f
+};
+static GLfloat quadUVs[] = {
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+ 1.0f, 0.0f,
+ 0.0f, 0.0f,
+ 0.0f, 1.0f
+};
// ---------------------------------------------------------------------------
@@ -209,7 +255,6 @@
const int w = bitmapInfo.width;
const int h = bitmapInfo.height;
- GLint crop[4] = { 0, h, w, -h };
texture->w = w;
texture->h = h;
@@ -237,11 +282,10 @@
break;
}
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
return NO_ERROR;
}
@@ -263,7 +307,6 @@
const int w = bitmapInfo.width;
const int h = bitmapInfo.height;
- GLint crop[4] = { 0, h, w, -h };
int tw = 1 << (31 - __builtin_clz(w));
int th = 1 << (31 - __builtin_clz(h));
if (tw < w) tw <<= 1;
@@ -297,7 +340,10 @@
break;
}
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
*width = w;
*height = h;
@@ -470,7 +516,9 @@
eglInitialize(display, nullptr, nullptr);
EGLConfig config = getEglConfig(display);
EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr);
- EGLContext context = eglCreateContext(display, config, nullptr, nullptr);
+ // Initialize egl context with client version number 2.0.
+ EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+ EGLContext context = eglCreateContext(display, config, nullptr, contextAttributes);
EGLint w, h;
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
@@ -503,11 +551,6 @@
void BootAnimation::projectSceneToWindow() {
glViewport(0, 0, mWidth, mHeight);
glScissor(0, 0, mWidth, mHeight);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrthof(0, static_cast<float>(mWidth), 0, static_cast<float>(mHeight), -1, 1);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
}
void BootAnimation::resizeSurface(int newWidth, int newHeight) {
@@ -600,8 +643,68 @@
}
}
+GLuint compileShader(GLenum shaderType, const GLchar *source) {
+ GLuint shader = glCreateShader(shaderType);
+ glShaderSource(shader, 1, &source, 0);
+ glCompileShader(shader);
+ GLint isCompiled = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
+ if (isCompiled == GL_FALSE) {
+ SLOGE("Compile shader failed. Shader type: %d", shaderType);
+ return 0;
+ }
+ return shader;
+}
+
+GLuint linkShader(GLuint vertexShader, GLuint fragmentShader) {
+ GLuint program = glCreateProgram();
+ glAttachShader(program, vertexShader);
+ glAttachShader(program, fragmentShader);
+ glLinkProgram(program);
+ GLint isLinked = 0;
+ glGetProgramiv(program, GL_LINK_STATUS, (int *)&isLinked);
+ if (isLinked == GL_FALSE) {
+ SLOGE("Linking shader failed. Shader handles: vert %d, frag %d",
+ vertexShader, fragmentShader);
+ return 0;
+ }
+ return program;
+}
+
+void BootAnimation::initShaders() {
+ GLuint vertexShader = compileShader(GL_VERTEX_SHADER, (const GLchar *)VERTEX_SHADER_SOURCE);
+ GLuint imageFragmentShader =
+ compileShader(GL_FRAGMENT_SHADER, (const GLchar *)IMAGE_FRAG_SHADER_SOURCE);
+ GLuint textFragmentShader =
+ compileShader(GL_FRAGMENT_SHADER, (const GLchar *)TEXT_FRAG_SHADER_SOURCE);
+
+ // Initialize image shader.
+ mImageShader = linkShader(vertexShader, imageFragmentShader);
+ GLint positionLocation = glGetAttribLocation(mImageShader, A_POSITION);
+ GLint uvLocation = glGetAttribLocation(mImageShader, A_UV);
+ mImageTextureLocation = glGetUniformLocation(mImageShader, U_TEXTURE);
+ mImageFadeLocation = glGetUniformLocation(mImageShader, U_FADE);
+ glEnableVertexAttribArray(positionLocation);
+ glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, quadPositions);
+ glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs);
+ glEnableVertexAttribArray(uvLocation);
+
+ // Initialize text shader.
+ mTextShader = linkShader(vertexShader, textFragmentShader);
+ positionLocation = glGetAttribLocation(mTextShader, A_POSITION);
+ uvLocation = glGetAttribLocation(mTextShader, A_UV);
+ mTextTextureLocation = glGetUniformLocation(mTextShader, U_TEXTURE);
+ mTextCropAreaLocation = glGetUniformLocation(mTextShader, U_CROP_AREA);
+ glEnableVertexAttribArray(positionLocation);
+ glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, quadPositions);
+ glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs);
+ glEnableVertexAttribArray(uvLocation);
+}
+
bool BootAnimation::threadLoop() {
bool result;
+ initShaders();
+
// We have no bootanimation file, so we use the stock android logo
// animation.
if (mZipFileName.isEmpty()) {
@@ -623,6 +726,8 @@
}
bool BootAnimation::android() {
+ glActiveTexture(GL_TEXTURE0);
+
SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
elapsedRealtime());
initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
@@ -631,19 +736,14 @@
mCallbacks->init({});
// clear screen
- glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(mDisplay, mSurface);
- glEnable(GL_TEXTURE_2D);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-
// Blend state
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
const nsecs_t startTime = systemTime();
do {
@@ -666,12 +766,12 @@
glEnable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
- glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h);
- glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
+ drawTexturedQuad(x, yc, mAndroid[1].w, mAndroid[1].h);
+ drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h);
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
- glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
+ drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h);
EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
if (res == EGL_FALSE)
@@ -798,10 +898,10 @@
status = initTexture(font->map, &font->texture.w, &font->texture.h);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else if (fallback != nullptr) {
status = initTexture(&font->texture, mAssets, fallback);
} else {
@@ -816,40 +916,11 @@
return status;
}
-void BootAnimation::fadeFrame(const int frameLeft, const int frameBottom, const int frameWidth,
- const int frameHeight, const Animation::Part& part,
- const int fadedFramesCount) {
- glEnable(GL_BLEND);
- glEnableClientState(GL_VERTEX_ARRAY);
- glDisable(GL_TEXTURE_2D);
- // avoid creating a hole due to mixing result alpha with GL_REPLACE texture
- glBlendFuncSeparateOES(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
-
- const float alpha = static_cast<float>(fadedFramesCount) / part.framesToFadeCount;
- glColor4f(part.backgroundColor[0], part.backgroundColor[1], part.backgroundColor[2], alpha);
-
- const float frameStartX = static_cast<float>(frameLeft);
- const float frameStartY = static_cast<float>(frameBottom);
- const float frameEndX = frameStartX + frameWidth;
- const float frameEndY = frameStartY + frameHeight;
- const GLfloat frameRect[] = {
- frameStartX, frameStartY,
- frameEndX, frameStartY,
- frameEndX, frameEndY,
- frameStartX, frameEndY
- };
- glVertexPointer(2, GL_FLOAT, 0, frameRect);
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_TEXTURE_2D);
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisable(GL_BLEND);
-}
-
void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) {
glEnable(GL_BLEND); // Allow us to draw on top of the animation
glBindTexture(GL_TEXTURE_2D, font.texture.name);
+ glUseProgram(mTextShader);
+ glUniform1i(mTextTextureLocation, 0);
const int len = strlen(str);
const int strWidth = font.char_width * len;
@@ -865,8 +936,6 @@
*y = mHeight + *y - font.char_height;
}
- int cropRect[4] = { 0, 0, font.char_width, -font.char_height };
-
for (int i = 0; i < len; i++) {
char c = str[i];
@@ -878,13 +947,13 @@
const int charPos = (c - FONT_BEGIN_CHAR); // Position in the list of valid characters
const int row = charPos / FONT_NUM_COLS;
const int col = charPos % FONT_NUM_COLS;
- cropRect[0] = col * font.char_width; // Left of column
- cropRect[1] = row * font.char_height * 2; // Top of row
- // Move down to bottom of regular (one char_heigh) or bold (two char_heigh) line
- cropRect[1] += bold ? 2 * font.char_height : font.char_height;
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
-
- glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height);
+ // Bold fonts are expected in the second half of each row.
+ float v0 = (row + (bold ? 0.5f : 0.0f)) / FONT_NUM_ROWS;
+ float u0 = ((float)col) / FONT_NUM_COLS;
+ float v1 = v0 + 1.0f / FONT_NUM_ROWS / 2;
+ float u1 = u0 + 1.0f / FONT_NUM_COLS;
+ glUniform4f(mTextCropAreaLocation, u0, v0, u1, v1);
+ drawTexturedQuad(*x, *y, font.char_width, font.char_height);
*x += font.char_width;
}
@@ -1166,19 +1235,16 @@
// Blend required to draw time on top of animation frames.
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
- glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_TEXTURE_2D);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
bool clockFontInitialized = false;
if (mClockEnabled) {
clockFontInitialized =
@@ -1218,6 +1284,34 @@
(lastDisplayedProgress == 0 || lastDisplayedProgress == 100);
}
+// Linear mapping from range <a1, a2> to range <b1, b2>
+float mapLinear(float x, float a1, float a2, float b1, float b2) {
+ return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
+}
+
+void BootAnimation::drawTexturedQuad(float xStart, float yStart, float width, float height) {
+ // Map coordinates from screen space to world space.
+ float x0 = mapLinear(xStart, 0, mWidth, -1, 1);
+ float y0 = mapLinear(yStart, 0, mHeight, -1, 1);
+ float x1 = mapLinear(xStart + width, 0, mWidth, -1, 1);
+ float y1 = mapLinear(yStart + height, 0, mHeight, -1, 1);
+ // Update quad vertex positions.
+ quadPositions[0] = x0;
+ quadPositions[1] = y0;
+ quadPositions[2] = x1;
+ quadPositions[3] = y0;
+ quadPositions[4] = x1;
+ quadPositions[5] = y1;
+ quadPositions[6] = x1;
+ quadPositions[7] = y1;
+ quadPositions[8] = x0;
+ quadPositions[9] = y1;
+ quadPositions[10] = x0;
+ quadPositions[11] = y0;
+ glDrawArrays(GL_TRIANGLES, 0,
+ sizeof(quadPositions) / sizeof(quadPositions[0]) / 2);
+}
+
bool BootAnimation::playAnimation(const Animation& animation) {
const size_t pcount = animation.parts.size();
nsecs_t frameDuration = s2ns(1) / animation.fps;
@@ -1230,7 +1324,6 @@
for (size_t i=0 ; i<pcount ; i++) {
const Animation::Part& part(animation.parts[i]);
const size_t fcount = part.frames.size();
- glBindTexture(GL_TEXTURE_2D, 0);
// Handle animation package
if (part.animation != nullptr) {
@@ -1272,12 +1365,8 @@
if (r > 0) {
glBindTexture(GL_TEXTURE_2D, frame.tid);
} else {
- if (part.count != 1) {
- glGenTextures(1, &frame.tid);
- glBindTexture(GL_TEXTURE_2D, frame.tid);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- }
+ glGenTextures(1, &frame.tid);
+ glBindTexture(GL_TEXTURE_2D, frame.tid);
int w, h;
initTexture(frame.map, &w, &h);
}
@@ -1300,16 +1389,21 @@
// specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
// which is equivalent to mHeight - (yc + frame.trimHeight)
const int frameDrawY = mHeight - (yc + frame.trimHeight);
- glDrawTexiOES(xc, frameDrawY, 0, frame.trimWidth, frame.trimHeight);
+ float fade = 0;
// if the part hasn't been stopped yet then continue fading if necessary
if (exitPending() && part.hasFadingPhase()) {
- fadeFrame(xc, frameDrawY, frame.trimWidth, frame.trimHeight, part,
- ++fadedFramesCount);
+ fade = static_cast<float>(++fadedFramesCount) / part.framesToFadeCount;
if (fadedFramesCount >= part.framesToFadeCount) {
fadedFramesCount = MAX_FADED_FRAMES_COUNT; // no more fading
}
}
+ glUseProgram(mImageShader);
+ glUniform1i(mImageTextureLocation, 0);
+ glUniform1f(mImageFadeLocation, fade);
+ glEnable(GL_BLEND);
+ drawTexturedQuad(xc, frameDrawY, frame.trimWidth, frame.trimHeight);
+ glDisable(GL_BLEND);
if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index f8a31c6..7b616d9 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -31,7 +31,7 @@
#include <binder/IBinder.h>
#include <EGL/egl.h>
-#include <GLES/gl.h>
+#include <GLES2/gl2.h>
namespace android {
@@ -166,6 +166,7 @@
status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
status_t initTexture(FileMap* map, int* width, int* height);
status_t initFont(Font* font, const char* fallback);
+ void initShaders();
bool android();
bool movie();
void drawText(const char* str, const Font& font, bool bold, int* x, int* y);
@@ -173,6 +174,7 @@
void drawProgress(int percent, const Font& font, const int xPos, const int yPos);
void fadeFrame(int frameLeft, int frameBottom, int frameWidth, int frameHeight,
const Animation::Part& part, int fadedFramesCount);
+ void drawTexturedQuad(float xStart, float yStart, float width, float height);
bool validClock(const Animation::Part& part);
Animation* loadAnimation(const String8&);
bool playAnimation(const Animation&);
@@ -218,6 +220,12 @@
sp<TimeCheckThread> mTimeCheckThread = nullptr;
sp<Callbacks> mCallbacks;
Animation* mAnimation = nullptr;
+ GLuint mImageShader;
+ GLuint mTextShader;
+ GLuint mImageFadeLocation;
+ GLuint mImageTextureLocation;
+ GLuint mTextCropAreaLocation;
+ GLuint mTextTextureLocation;
};
// ---------------------------------------------------------------------------
diff --git a/core/api/current.txt b/core/api/current.txt
index 7a00119..a2dd805 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -7937,6 +7937,7 @@
method public static final long getMinFlexMillis();
method public long getMinLatencyMillis();
method public static final long getMinPeriodMillis();
+ method public long getMinimumNetworkChunkBytes();
method @Deprecated public int getNetworkType();
method @Nullable public android.net.NetworkRequest getRequiredNetwork();
method @NonNull public android.content.ComponentName getService();
@@ -7979,6 +7980,7 @@
method public android.app.job.JobInfo.Builder setExtras(@NonNull android.os.PersistableBundle);
method @Deprecated public android.app.job.JobInfo.Builder setImportantWhileForeground(boolean);
method public android.app.job.JobInfo.Builder setMinimumLatency(long);
+ method @NonNull public android.app.job.JobInfo.Builder setMinimumNetworkChunkBytes(long);
method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
method public android.app.job.JobInfo.Builder setPeriodic(long);
method public android.app.job.JobInfo.Builder setPeriodic(long, long);
@@ -8071,11 +8073,13 @@
public final class JobWorkItem implements android.os.Parcelable {
ctor public JobWorkItem(android.content.Intent);
ctor public JobWorkItem(android.content.Intent, long, long);
+ ctor public JobWorkItem(@Nullable android.content.Intent, long, long, long);
method public int describeContents();
method public int getDeliveryCount();
method public long getEstimatedNetworkDownloadBytes();
method public long getEstimatedNetworkUploadBytes();
method public android.content.Intent getIntent();
+ method public long getMinimumNetworkChunkBytes();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.job.JobWorkItem> CREATOR;
}
@@ -15261,9 +15265,11 @@
method public void clearContent();
method @NonNull public android.graphics.HardwareRenderer.FrameRenderRequest createRenderRequest();
method public void destroy();
+ method public static boolean isDrawingEnabled();
method public boolean isOpaque();
method public void notifyFramePending();
method public void setContentRoot(@Nullable android.graphics.RenderNode);
+ method public static void setDrawingEnabled(boolean);
method public void setLightSourceAlpha(@FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float);
method public void setLightSourceGeometry(float, float, float, float);
method public void setName(@NonNull String);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index c20b2e0..0d15a03 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -2213,17 +2213,17 @@
public final class BluetoothLeScanner {
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(android.os.WorkSource, android.bluetooth.le.ScanCallback);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.os.WorkSource, android.bluetooth.le.ScanCallback);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
}
- public final class ResultStorageDescriptor implements android.os.Parcelable {
- ctor public ResultStorageDescriptor(int, int, int);
- method public int describeContents();
- method public int getLength();
- method public int getOffset();
- method public int getType();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.ResultStorageDescriptor> CREATOR;
+ @Deprecated public final class ResultStorageDescriptor implements android.os.Parcelable {
+ ctor @Deprecated public ResultStorageDescriptor(int, int, int);
+ method @Deprecated public int describeContents();
+ method @Deprecated public int getLength();
+ method @Deprecated public int getOffset();
+ method @Deprecated public int getType();
+ method @Deprecated public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.ResultStorageDescriptor> CREATOR;
}
public final class ScanFilter implements android.os.Parcelable {
@@ -2247,10 +2247,10 @@
method public android.bluetooth.le.ScanSettings.Builder setScanResultType(int);
}
- public final class TruncatedFilter {
- ctor public TruncatedFilter(android.bluetooth.le.ScanFilter, java.util.List<android.bluetooth.le.ResultStorageDescriptor>);
- method public android.bluetooth.le.ScanFilter getFilter();
- method public java.util.List<android.bluetooth.le.ResultStorageDescriptor> getStorageDescriptors();
+ @Deprecated public final class TruncatedFilter {
+ ctor @Deprecated public TruncatedFilter(android.bluetooth.le.ScanFilter, java.util.List<android.bluetooth.le.ResultStorageDescriptor>);
+ method @Deprecated public android.bluetooth.le.ScanFilter getFilter();
+ method @Deprecated public java.util.List<android.bluetooth.le.ResultStorageDescriptor> getStorageDescriptors();
}
}
@@ -9083,6 +9083,7 @@
public final class DeviceConfig {
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
+ method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean deleteProperty(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static boolean getBoolean(@NonNull String, @NonNull String, boolean);
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static float getFloat(@NonNull String, @NonNull String, float);
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static int getInt(@NonNull String, @NonNull String, int);
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 6c001f3..89d93ae 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -313,6 +313,10 @@
backend: {
rust: {
enabled: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt", // for virtualizationservice
+ ],
},
},
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 24fb76a..249a606 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2721,10 +2721,13 @@
// need to override their display in ResourcesManager.
baseContext.mForceDisplayOverrideInResources = false;
baseContext.mContextType = CONTEXT_TYPE_WINDOW_CONTEXT;
- baseContext.mDisplay = display;
final Resources windowContextResources = createWindowContextResources(baseContext);
baseContext.setResources(windowContextResources);
+ // Associate the display with window context resources so that configuration update from
+ // the server side will also apply to the display's metrics.
+ baseContext.mDisplay = ResourcesManager.getInstance()
+ .getAdjustedDisplay(display.getDisplayId(), windowContextResources);
return baseContext;
}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 313a340..b90b9a1 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -508,7 +508,6 @@
boolean stopBinderTrackingAndDump(in ParcelFileDescriptor fd);
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
void suppressResizeConfigChanges(boolean suppress);
- boolean isAppStartModeDisabled(int uid, in String packageName);
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
boolean unlockUser(int userid, in byte[] token, in byte[] secret,
in IProgressListener listener);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 86ea05b..ab88e6c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5380,14 +5380,15 @@
private void bindExpandButton(RemoteViews contentView, StandardTemplateParams p) {
// set default colors
- int textColor = getPrimaryTextColor(p);
- int pillColor = getColors(p).getProtectionColor();
+ int bgColor = getBackgroundColor(p);
+ int pillColor = Colors.flattenAlpha(getColors(p).getProtectionColor(), bgColor);
+ int textColor = Colors.flattenAlpha(getPrimaryTextColor(p), pillColor);
contentView.setInt(R.id.expand_button, "setDefaultTextColor", textColor);
contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor);
// Use different highlighted colors for conversations' unread count
if (p.mHighlightExpander) {
- textColor = getBackgroundColor(p);
- pillColor = getPrimaryAccentColor(p);
+ pillColor = Colors.flattenAlpha(getPrimaryAccentColor(p), bgColor);
+ textColor = Colors.flattenAlpha(bgColor, pillColor);
}
contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor);
contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor);
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index af75c69..bf3778d 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -1158,9 +1158,15 @@
} else {
activityResources.overrideConfig.unset();
}
+
// Update the Activity's override display id.
activityResources.overrideDisplayId = displayId;
+ // If a application info update was scheduled to occur in this process but has not
+ // occurred yet, apply it now so the resources objects will have updated paths if
+ // the assets sequence changed.
+ applyAllPendingAppInfoUpdates();
+
if (DEBUG) {
Throwable here = new Throwable();
here.fillInStackTrace();
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 1569e60..cac7639 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -29,11 +29,13 @@
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Build;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
+import android.view.DisplayCutout;
import android.window.TaskSnapshot;
import android.window.WindowContainerToken;
@@ -181,6 +183,15 @@
public PictureInPictureParams pictureInPictureParams;
/**
+ * The {@link Rect} copied from {@link DisplayCutout#getSafeInsets()} if the cutout is not of
+ * (LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES, LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS),
+ * {@code null} otherwise.
+ * @hide
+ */
+ @Nullable
+ public Rect displayCutoutInsets;
+
+ /**
* The activity type of the top activity in this task.
* @hide
*/
@@ -345,6 +356,7 @@
&& displayAreaFeatureId == that.displayAreaFeatureId
&& Objects.equals(positionInParent, that.positionInParent)
&& Objects.equals(pictureInPictureParams, that.pictureInPictureParams)
+ && Objects.equals(displayCutoutInsets, that.displayCutoutInsets)
&& getWindowingMode() == that.getWindowingMode()
&& Objects.equals(taskDescription, that.taskDescription)
&& isFocused == that.isFocused
@@ -396,6 +408,7 @@
token = WindowContainerToken.CREATOR.createFromParcel(source);
topActivityType = source.readInt();
pictureInPictureParams = source.readTypedObject(PictureInPictureParams.CREATOR);
+ displayCutoutInsets = source.readTypedObject(Rect.CREATOR);
topActivityInfo = source.readTypedObject(ActivityInfo.CREATOR);
isResizeable = source.readBoolean();
source.readBinderList(launchCookies);
@@ -435,6 +448,7 @@
token.writeToParcel(dest, flags);
dest.writeInt(topActivityType);
dest.writeTypedObject(pictureInPictureParams, flags);
+ dest.writeTypedObject(displayCutoutInsets, flags);
dest.writeTypedObject(topActivityInfo, flags);
dest.writeBoolean(isResizeable);
dest.writeBinderList(launchCookies);
@@ -465,6 +479,7 @@
+ " token=" + token
+ " topActivityType=" + topActivityType
+ " pictureInPictureParams=" + pictureInPictureParams
+ + " displayCutoutSafeInsets=" + displayCutoutInsets
+ " topActivityInfo=" + topActivityInfo
+ " launchCookies=" + launchCookies
+ " positionInParent=" + positionInParent
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 34aac8b..ee173db 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -151,7 +151,7 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void startScan(List<ScanFilter> filters, ScanSettings settings,
final ScanCallback callback) {
- startScan(filters, settings, null, callback, /*callbackIntent=*/ null, null);
+ startScan(filters, settings, null, callback, /*callbackIntent=*/ null);
}
/**
@@ -185,7 +185,7 @@
@NonNull PendingIntent callbackIntent) {
return startScan(filters,
settings != null ? settings : new ScanSettings.Builder().build(),
- null, null, callbackIntent, null);
+ null, null, callbackIntent);
}
/**
@@ -231,14 +231,13 @@
@SuppressLint("AndroidFrameworkRequiresPermission")
public void startScanFromSource(List<ScanFilter> filters, ScanSettings settings,
final WorkSource workSource, final ScanCallback callback) {
- startScan(filters, settings, workSource, callback, null, null);
+ startScan(filters, settings, workSource, callback, null);
}
@RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
private int startScan(List<ScanFilter> filters, ScanSettings settings,
final WorkSource workSource, final ScanCallback callback,
- final PendingIntent callbackIntent,
- List<List<ResultStorageDescriptor>> resultStorages) {
+ final PendingIntent callbackIntent) {
BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
if (callback == null && callbackIntent == null) {
throw new IllegalArgumentException("callback is null");
@@ -274,7 +273,7 @@
}
if (callback != null) {
BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
- settings, workSource, callback, resultStorages);
+ settings, workSource, callback);
wrapper.startRegistration();
} else {
try {
@@ -357,8 +356,11 @@
/**
* Start truncated scan.
*
+ * @deprecated this is not used anywhere
+ *
* @hide
*/
+ @Deprecated
@SystemApi
@RequiresBluetoothScanPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
@@ -366,13 +368,10 @@
final ScanCallback callback) {
int filterSize = truncatedFilters.size();
List<ScanFilter> scanFilters = new ArrayList<ScanFilter>(filterSize);
- List<List<ResultStorageDescriptor>> scanStorages =
- new ArrayList<List<ResultStorageDescriptor>>(filterSize);
for (TruncatedFilter filter : truncatedFilters) {
scanFilters.add(filter.getFilter());
- scanStorages.add(filter.getStorageDescriptors());
}
- startScan(scanFilters, settings, null, callback, null, scanStorages);
+ startScan(scanFilters, settings, null, callback, null);
}
/**
@@ -397,7 +396,6 @@
private final WorkSource mWorkSource;
private ScanSettings mSettings;
private IBluetoothGatt mBluetoothGatt;
- private List<List<ResultStorageDescriptor>> mResultStorages;
// mLeHandle 0: not registered
// -2: registration failed because app is scanning to frequently
@@ -407,15 +405,13 @@
public BleScanCallbackWrapper(IBluetoothGatt bluetoothGatt,
List<ScanFilter> filters, ScanSettings settings,
- WorkSource workSource, ScanCallback scanCallback,
- List<List<ResultStorageDescriptor>> resultStorages) {
+ WorkSource workSource, ScanCallback scanCallback) {
mBluetoothGatt = bluetoothGatt;
mFilters = filters;
mSettings = settings;
mWorkSource = workSource;
mScanCallback = scanCallback;
mScannerId = 0;
- mResultStorages = resultStorages;
}
public void startRegistration() {
@@ -493,7 +489,7 @@
} else {
mScannerId = scannerId;
mBluetoothGatt.startScan(mScannerId, mSettings, mFilters,
- mResultStorages, mAttributionSource);
+ mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "fail to start le scan: " + e);
diff --git a/core/java/android/bluetooth/le/ResultStorageDescriptor.java b/core/java/android/bluetooth/le/ResultStorageDescriptor.java
index 796c815..f650489 100644
--- a/core/java/android/bluetooth/le/ResultStorageDescriptor.java
+++ b/core/java/android/bluetooth/le/ResultStorageDescriptor.java
@@ -23,8 +23,11 @@
/**
* Describes the way to store scan result.
*
+ * @deprecated this is not used anywhere
+ *
* @hide
*/
+@Deprecated
@SystemApi
public final class ResultStorageDescriptor implements Parcelable {
private int mType;
diff --git a/core/java/android/bluetooth/le/TruncatedFilter.java b/core/java/android/bluetooth/le/TruncatedFilter.java
index 93f526b..2592588 100644
--- a/core/java/android/bluetooth/le/TruncatedFilter.java
+++ b/core/java/android/bluetooth/le/TruncatedFilter.java
@@ -24,8 +24,11 @@
/**
* A special scan filter that lets the client decide how the scan record should be stored.
*
+ * @deprecated this is not used anywhere
+ *
* @hide
*/
+@Deprecated
@SystemApi
@SuppressLint("AndroidFrameworkBluetoothPermission")
public final class TruncatedFilter {
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index d63ce0f..0e22705 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -152,6 +152,10 @@
AttributionSource(@NonNull Parcel in) {
this(AttributionSourceState.CREATOR.createFromParcel(in));
+
+ // Since we just unpacked this object as part of it transiting a Binder
+ // call, this is the perfect time to enforce that its UID can be trusted
+ enforceCallingUid();
}
/** @hide */
diff --git a/core/java/android/hardware/ISensorPrivacyManager.aidl b/core/java/android/hardware/ISensorPrivacyManager.aidl
index 6105c26..debc074 100644
--- a/core/java/android/hardware/ISensorPrivacyManager.aidl
+++ b/core/java/android/hardware/ISensorPrivacyManager.aidl
@@ -46,6 +46,6 @@
void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
// =============== End of transactions used on native side as well ============================
- void suppressIndividualSensorPrivacyReminders(int userId, String packageName, IBinder token,
+ void suppressIndividualSensorPrivacyReminders(int userId, int sensor, IBinder token,
boolean suppress);
}
\ No newline at end of file
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index c392fbb..b7d95e7 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -461,9 +461,9 @@
* @hide
*/
@RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
- public void suppressSensorPrivacyReminders(@NonNull String packageName,
+ public void suppressSensorPrivacyReminders(int sensor,
boolean suppress) {
- suppressSensorPrivacyReminders(packageName, suppress, mContext.getUserId());
+ suppressSensorPrivacyReminders(sensor, suppress, mContext.getUserId());
}
/**
@@ -476,10 +476,10 @@
* @hide
*/
@RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
- public void suppressSensorPrivacyReminders(@NonNull String packageName,
+ public void suppressSensorPrivacyReminders(int sensor,
boolean suppress, @UserIdInt int userId) {
try {
- mService.suppressIndividualSensorPrivacyReminders(userId, packageName,
+ mService.suppressIndividualSensorPrivacyReminders(userId, sensor,
token, suppress);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 0cb996b..dc1a50f 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -1382,12 +1382,7 @@
String[] msgArray = context.getResources().getStringArray(
com.android.internal.R.array.fingerprint_error_vendor);
if (vendorCode < msgArray.length) {
- if (Build.IS_ENG || Build.IS_USERDEBUG) {
- return msgArray[vendorCode];
- } else {
- return context.getString(
- com.android.internal.R.string.fingerprint_error_unable_to_process);
- }
+ return msgArray[vendorCode];
}
}
}
@@ -1427,12 +1422,7 @@
String[] msgArray = context.getResources().getStringArray(
com.android.internal.R.array.fingerprint_acquired_vendor);
if (vendorCode < msgArray.length) {
- if (Build.IS_ENG || Build.IS_USERDEBUG) {
- return msgArray[vendorCode];
- } else {
- return context.getString(
- com.android.internal.R.string.fingerprint_error_unable_to_process);
- }
+ return msgArray[vendorCode];
}
}
break;
diff --git a/core/java/android/hardware/location/ContextHubClientCallback.java b/core/java/android/hardware/location/ContextHubClientCallback.java
index 35d00f0..9309c5b 100644
--- a/core/java/android/hardware/location/ContextHubClientCallback.java
+++ b/core/java/android/hardware/location/ContextHubClientCallback.java
@@ -68,8 +68,11 @@
/**
* Callback invoked when a nanoapp is dynamically loaded at the attached Context Hub through
- * the {@link android.hardware.location.ContextHubManager}. This callback is not invoked for a
- * nanoapp that is loaded internally by CHRE (e.g. nanoapps that are preloaded by the system).
+ * the {@link android.hardware.location.ContextHubManager}.
+ *
+ * NOTE: This callback is <b>not</b> invoked for a nanoapp that is loaded internally by CHRE
+ * (e.g. nanoapps that are preloaded by the system). To check the availability of these
+ * nanoapps, use the {@link ContextHubManager#queryNanoApps(ContextHubInfo)} API.
*
* @param client the client that is associated with this callback
* @param nanoAppId the ID of the nanoapp that had been loaded
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index f69a7d7..9af0e09 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -128,7 +128,8 @@
public static final int AUTHORIZATION_GRANTED = 2;
/**
- * Constants describing the type of events from a Context Hub.
+ * Constants describing the type of events from a Context Hub, as defined in
+ * {@link ContextHubClientCallback}.
* {@hide}
*/
@Retention(RetentionPolicy.SOURCE)
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 17d4ae6..9db41c4 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -25,13 +25,10 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
-import android.util.proto.ProtoOutputStream;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodSession;
import android.window.WindowProviderService;
@@ -216,16 +213,6 @@
public abstract AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
/**
- * Dumps the internal state of IME to a protocol buffer output stream.
- *
- * @param proto ProtoOutputStream to dump data to.
- * @param icProto {@link InputConnection} call data in proto format.
- * @hide
- */
- @SuppressWarnings("HiddenAbstractMethod")
- public abstract void dumpProtoInternal(ProtoOutputStream proto, ProtoOutputStream icProto);
-
- /**
* Implement this to handle {@link android.os.Binder#dump Binder.dump()}
* calls on your input method.
*/
@@ -238,9 +225,36 @@
if (mInputMethod == null) {
mInputMethod = onCreateInputMethodInterface();
}
- return new IInputMethodWrapper(this, mInputMethod);
+ return new IInputMethodWrapper(createInputMethodServiceInternal(), mInputMethod);
}
-
+
+ /**
+ * Used to inject custom {@link InputMethodServiceInternal}.
+ *
+ * @return the {@link InputMethodServiceInternal} to be used.
+ */
+ @NonNull
+ InputMethodServiceInternal createInputMethodServiceInternal() {
+ return new InputMethodServiceInternal() {
+ /**
+ * {@inheritDoc}
+ */
+ @NonNull
+ @Override
+ public Context getContext() {
+ return AbstractInputMethodService.this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ AbstractInputMethodService.this.dump(fd, fout, args);
+ }
+ };
+ }
+
/**
* Implement this to handle trackball events on your input method.
*
@@ -263,35 +277,6 @@
return false;
}
- /**
- * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
- * permission to the content.
- *
- * <p>Default implementation does nothing.</p>
- *
- * @param inputContentInfo Content to be temporarily exposed from the input method to the
- * application.
- * This cannot be {@code null}.
- * @param inputConnection {@link InputConnection} with which
- * {@link InputConnection#commitContent(InputContentInfo, int, android.os.Bundle)} will be
- * called.
- * @return {@code false} if we cannot allow a temporary access permission.
- * @hide
- */
- public void exposeContent(@NonNull InputContentInfo inputContentInfo,
- @NonNull InputConnection inputConnection) {
- return;
- }
-
- /**
- * Called when the user took some actions that should be taken into consideration to update the
- * MRU list for input method rotation.
- *
- * @hide
- */
- public void notifyUserActionIfNecessary() {
- }
-
// TODO(b/149463653): remove it in T. We missed the API deadline in S.
/** @hide */
@Override
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 99e439a..90990b4 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -76,7 +76,7 @@
private static final int DO_CHANGE_INPUTMETHOD_SUBTYPE = 80;
private static final int DO_CREATE_INLINE_SUGGESTIONS_REQUEST = 90;
- final WeakReference<AbstractInputMethodService> mTarget;
+ final WeakReference<InputMethodServiceInternal> mTarget;
final Context mContext;
@UnsupportedAppUsage
final HandlerCaller mCaller;
@@ -129,12 +129,12 @@
}
}
- public IInputMethodWrapper(AbstractInputMethodService context, InputMethod inputMethod) {
- mTarget = new WeakReference<>(context);
- mContext = context.getApplicationContext();
+ IInputMethodWrapper(InputMethodServiceInternal imsInternal, InputMethod inputMethod) {
+ mTarget = new WeakReference<>(imsInternal);
+ mContext = imsInternal.getContext().getApplicationContext();
mCaller = new HandlerCaller(mContext, null, this, true /*asyncHandler*/);
mInputMethod = new WeakReference<>(inputMethod);
- mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
+ mTargetSdkVersion = imsInternal.getContext().getApplicationInfo().targetSdkVersion;
}
@MainThread
@@ -149,7 +149,7 @@
switch (msg.what) {
case DO_DUMP: {
- AbstractInputMethodService target = mTarget.get();
+ InputMethodServiceInternal target = mTarget.get();
if (target == null) {
return;
}
@@ -251,11 +251,11 @@
@BinderThread
@Override
protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
- AbstractInputMethodService target = mTarget.get();
+ InputMethodServiceInternal target = mTarget.get();
if (target == null) {
return;
}
- if (target.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ if (target.getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
fout.println("Permission Denial: can't dump InputMethodManager from from pid="
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 42fa9fb..dadea67 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -55,7 +55,6 @@
import static java.lang.annotation.RetentionPolicy.SOURCE;
-import android.annotation.AnyThread;
import android.annotation.CallSuper;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
@@ -94,7 +93,6 @@
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
-import android.util.imetracing.ImeTracing;
import android.util.proto.ProtoOutputStream;
import android.view.Gravity;
import android.view.KeyCharacterMap;
@@ -133,6 +131,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
+import com.android.internal.inputmethod.ImeTracing;
import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
import com.android.internal.view.IInlineSuggestionsRequestCallback;
@@ -740,7 +739,7 @@
return;
}
ImeTracing.getInstance().triggerServiceDump(
- "InputMethodService.InputMethodImpl#hideSoftInput", InputMethodService.this,
+ "InputMethodService.InputMethodImpl#hideSoftInput", mDumper,
null /* icProto */);
final boolean wasVisible = isInputViewShown();
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput");
@@ -797,7 +796,7 @@
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput");
ImeTracing.getInstance().triggerServiceDump(
- "InputMethodService.InputMethodImpl#showSoftInput", InputMethodService.this,
+ "InputMethodService.InputMethodImpl#showSoftInput", mDumper,
null /* icProto */);
final boolean wasVisible = isInputViewShown();
if (dispatchOnShowInputRequested(flags, false)) {
@@ -2222,7 +2221,7 @@
return;
}
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", this,
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", mDumper,
null /* icProto */);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow");
mDecorViewWasVisible = mDecorViewVisible;
@@ -2301,7 +2300,7 @@
*/
private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible) {
ImeTracing.getInstance().triggerServiceDump(
- "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", this,
+ "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", mDumper,
null /* icProto */);
if (setVisible) {
cancelImeSurfaceRemoval();
@@ -2330,7 +2329,7 @@
public void hideWindow() {
if (DEBUG) Log.v(TAG, "CALL: hideWindow");
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", this,
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper,
null /* icProto */);
mWindowVisible = false;
finishViews(false /* finishingInput */);
@@ -2403,7 +2402,7 @@
void doFinishInput() {
if (DEBUG) Log.v(TAG, "CALL: doFinishInput");
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#doFinishInput", this,
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#doFinishInput", mDumper,
null /* icProto */);
finishViews(true /* finishingInput */);
if (mInputStarted) {
@@ -2420,7 +2419,7 @@
if (!restarting && mInputStarted) {
doFinishInput();
}
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", this,
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", mDumper,
null /* icProto */);
mInputStarted = true;
mStartedInputConnection = ic;
@@ -2580,7 +2579,7 @@
* @param flags Provides additional operating flags.
*/
public void requestHideSelf(int flags) {
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", this,
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", mDumper,
null /* icProto */);
mPrivOps.hideMySoftInput(flags);
}
@@ -2594,7 +2593,7 @@
* @param flags Provides additional operating flags.
*/
public final void requestShowSelf(int flags) {
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", this,
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", mDumper,
null /* icProto */);
mPrivOps.showMySoftInput(flags);
}
@@ -3281,67 +3280,91 @@
}
/**
- * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
- * permission to the content.
+ * Used to inject custom {@link InputMethodServiceInternal}.
*
- * @param inputContentInfo Content to be temporarily exposed from the input method to the
- * application.
- * This cannot be {@code null}.
- * @param inputConnection {@link InputConnection} with which
- * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} will be called.
- * @hide
+ * @return the {@link InputMethodServiceInternal} to be used.
*/
+ @NonNull
@Override
- public final void exposeContent(@NonNull InputContentInfo inputContentInfo,
- @NonNull InputConnection inputConnection) {
- if (inputConnection == null) {
- return;
- }
- if (getCurrentInputConnection() != inputConnection) {
- return;
- }
- exposeContentInternal(inputContentInfo, getCurrentInputEditorInfo());
- }
-
- /**
- * {@inheritDoc}
- * @hide
- */
- @AnyThread
- @Override
- public final void notifyUserActionIfNecessary() {
- synchronized (mLock) {
- if (mNotifyUserActionSent) {
- return;
+ final InputMethodServiceInternal createInputMethodServiceInternal() {
+ return new InputMethodServiceInternal() {
+ /**
+ * {@inheritDoc}
+ */
+ @NonNull
+ @Override
+ public Context getContext() {
+ return InputMethodService.this;
}
- mPrivOps.notifyUserActionAsync();
- mNotifyUserActionSent = true;
- }
- }
- /**
- * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
- * permission to the content.
- *
- * <p>See {@link android.inputmethodservice.InputMethodService#exposeContent(InputContentInfo,
- * InputConnection)} for details.</p>
- *
- * @param inputContentInfo Content to be temporarily exposed from the input method to the
- * application.
- * This cannot be {@code null}.
- * @param editorInfo The editor that receives {@link InputContentInfo}.
- */
- private void exposeContentInternal(@NonNull InputContentInfo inputContentInfo,
- @NonNull EditorInfo editorInfo) {
- final Uri contentUri = inputContentInfo.getContentUri();
- final IInputContentUriToken uriToken =
- mPrivOps.createInputContentUriToken(contentUri, editorInfo.packageName);
- if (uriToken == null) {
- Log.e(TAG, "createInputContentAccessToken failed. contentUri=" + contentUri.toString()
- + " packageName=" + editorInfo.packageName);
- return;
- }
- inputContentInfo.setUriToken(uriToken);
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void exposeContent(@NonNull InputContentInfo inputContentInfo,
+ @NonNull InputConnection inputConnection) {
+ if (inputConnection == null) {
+ return;
+ }
+ if (getCurrentInputConnection() != inputConnection) {
+ return;
+ }
+ exposeContentInternal(inputContentInfo, getCurrentInputEditorInfo());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void notifyUserActionIfNecessary() {
+ synchronized (mLock) {
+ if (mNotifyUserActionSent) {
+ return;
+ }
+ mPrivOps.notifyUserActionAsync();
+ mNotifyUserActionSent = true;
+ }
+ }
+
+ /**
+ * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
+ * permission to the content.
+ *
+ * <p>See {@link #exposeContent(InputContentInfo, InputConnection)} for details.</p>
+ *
+ * @param inputContentInfo Content to be temporarily exposed from the input method to
+ * the application. This cannot be {@code null}.
+ * @param editorInfo The editor that receives {@link InputContentInfo}.
+ */
+ private void exposeContentInternal(@NonNull InputContentInfo inputContentInfo,
+ @NonNull EditorInfo editorInfo) {
+ final Uri contentUri = inputContentInfo.getContentUri();
+ final IInputContentUriToken uriToken =
+ mPrivOps.createInputContentUriToken(contentUri, editorInfo.packageName);
+ if (uriToken == null) {
+ Log.e(TAG, "createInputContentAccessToken failed. contentUri="
+ + contentUri.toString() + " packageName=" + editorInfo.packageName);
+ return;
+ }
+ inputContentInfo.setUriToken(uriToken);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter fout, String[]args) {
+ InputMethodService.this.dump(fd, fout, args);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void triggerServiceDump(String where, @Nullable byte[] icProto) {
+ ImeTracing.getInstance().triggerServiceDump(where, mDumper, icProto);
+ }
+ };
}
private int mapToImeWindowStatus() {
@@ -3411,42 +3434,44 @@
p.println(" mSettingsObserver=" + mSettingsObserver);
}
- /**
- * @hide
- */
- @Override
- public final void dumpProtoInternal(ProtoOutputStream proto, ProtoOutputStream icProto) {
- final long token = proto.start(InputMethodServiceTraceProto.INPUT_METHOD_SERVICE);
- mWindow.dumpDebug(proto, SOFT_INPUT_WINDOW);
- proto.write(VIEWS_CREATED, mViewsCreated);
- proto.write(DECOR_VIEW_VISIBLE, mDecorViewVisible);
- proto.write(DECOR_VIEW_WAS_VISIBLE, mDecorViewWasVisible);
- proto.write(WINDOW_VISIBLE, mWindowVisible);
- proto.write(IN_SHOW_WINDOW, mInShowWindow);
- proto.write(CONFIGURATION, getResources().getConfiguration().toString());
- proto.write(TOKEN, Objects.toString(mToken));
- proto.write(INPUT_BINDING, Objects.toString(mInputBinding));
- proto.write(INPUT_STARTED, mInputStarted);
- proto.write(INPUT_VIEW_STARTED, mInputViewStarted);
- proto.write(CANDIDATES_VIEW_STARTED, mCandidatesViewStarted);
- if (mInputEditorInfo != null) {
- mInputEditorInfo.dumpDebug(proto, INPUT_EDITOR_INFO);
+ private final ImeTracing.ServiceDumper mDumper = new ImeTracing.ServiceDumper() {
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void dumpToProto(ProtoOutputStream proto, @Nullable byte[] icProto) {
+ final long token = proto.start(InputMethodServiceTraceProto.INPUT_METHOD_SERVICE);
+ mWindow.dumpDebug(proto, SOFT_INPUT_WINDOW);
+ proto.write(VIEWS_CREATED, mViewsCreated);
+ proto.write(DECOR_VIEW_VISIBLE, mDecorViewVisible);
+ proto.write(DECOR_VIEW_WAS_VISIBLE, mDecorViewWasVisible);
+ proto.write(WINDOW_VISIBLE, mWindowVisible);
+ proto.write(IN_SHOW_WINDOW, mInShowWindow);
+ proto.write(CONFIGURATION, getResources().getConfiguration().toString());
+ proto.write(TOKEN, Objects.toString(mToken));
+ proto.write(INPUT_BINDING, Objects.toString(mInputBinding));
+ proto.write(INPUT_STARTED, mInputStarted);
+ proto.write(INPUT_VIEW_STARTED, mInputViewStarted);
+ proto.write(CANDIDATES_VIEW_STARTED, mCandidatesViewStarted);
+ if (mInputEditorInfo != null) {
+ mInputEditorInfo.dumpDebug(proto, INPUT_EDITOR_INFO);
+ }
+ proto.write(SHOW_INPUT_REQUESTED, mShowInputRequested);
+ proto.write(LAST_SHOW_INPUT_REQUESTED, mLastShowInputRequested);
+ proto.write(SHOW_INPUT_FLAGS, mShowInputFlags);
+ proto.write(CANDIDATES_VISIBILITY, mCandidatesVisibility);
+ proto.write(FULLSCREEN_APPLIED, mFullscreenApplied);
+ proto.write(IS_FULLSCREEN, mIsFullscreen);
+ proto.write(EXTRACT_VIEW_HIDDEN, mExtractViewHidden);
+ proto.write(EXTRACTED_TOKEN, mExtractedToken);
+ proto.write(IS_INPUT_VIEW_SHOWN, mIsInputViewShown);
+ proto.write(STATUS_ICON, mStatusIcon);
+ mTmpInsets.dumpDebug(proto, LAST_COMPUTED_INSETS);
+ proto.write(SETTINGS_OBSERVER, Objects.toString(mSettingsObserver));
+ if (icProto != null) {
+ proto.write(INPUT_CONNECTION_CALL, icProto);
+ }
+ proto.end(token);
}
- proto.write(SHOW_INPUT_REQUESTED, mShowInputRequested);
- proto.write(LAST_SHOW_INPUT_REQUESTED, mLastShowInputRequested);
- proto.write(SHOW_INPUT_FLAGS, mShowInputFlags);
- proto.write(CANDIDATES_VISIBILITY, mCandidatesVisibility);
- proto.write(FULLSCREEN_APPLIED, mFullscreenApplied);
- proto.write(IS_FULLSCREEN, mIsFullscreen);
- proto.write(EXTRACT_VIEW_HIDDEN, mExtractViewHidden);
- proto.write(EXTRACTED_TOKEN, mExtractedToken);
- proto.write(IS_INPUT_VIEW_SHOWN, mIsInputViewShown);
- proto.write(STATUS_ICON, mStatusIcon);
- mTmpInsets.dumpDebug(proto, LAST_COMPUTED_INSETS);
- proto.write(SETTINGS_OBSERVER, Objects.toString(mSettingsObserver));
- if (icProto != null) {
- proto.write(INPUT_CONNECTION_CALL, icProto.getBytes());
- }
- proto.end(token);
- }
+ };
}
diff --git a/core/java/android/inputmethodservice/InputMethodServiceInternal.java b/core/java/android/inputmethodservice/InputMethodServiceInternal.java
new file mode 100644
index 0000000..7cd4ff6
--- /dev/null
+++ b/core/java/android/inputmethodservice/InputMethodServiceInternal.java
@@ -0,0 +1,86 @@
+/*
+ * 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.inputmethodservice;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputContentInfo;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * A set of internal methods exposed by {@link InputMethodService} to be called only from other
+ * framework classes for internal use.
+ *
+ * <p>CAVEATS: {@link AbstractInputMethodService} does not support all the methods here.</p>
+ */
+interface InputMethodServiceInternal {
+ /**
+ * @return {@link Context} associated with the service.
+ */
+ @NonNull
+ Context getContext();
+
+ /**
+ * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
+ * permission to the content.
+ *
+ * @param inputContentInfo Content to be temporarily exposed from the input method to the
+ * application. This cannot be {@code null}.
+ * @param inputConnection {@link InputConnection} with which
+ * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)}
+ * will be called.
+ */
+ default void exposeContent(@NonNull InputContentInfo inputContentInfo,
+ @NonNull InputConnection inputConnection) {
+ }
+
+ /**
+ * Called when the user took some actions that should be taken into consideration to update the
+ * MRU list for input method rotation.
+ */
+ default void notifyUserActionIfNecessary() {
+ }
+
+ /**
+ * Called when the system is asking the IME to dump its information for debugging.
+ *
+ * <p>The caller is responsible for checking {@link android.Manifest.permission.DUMP}.</p>
+ *
+ * @param fd The raw file descriptor that the dump is being sent to.
+ * @param fout The file to which you should dump your state. This will be
+ * closed for you after you return.
+ * @param args additional arguments to the dump request.
+ */
+ default void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ }
+
+ /**
+ * Called with {@link com.android.internal.inputmethod.ImeTracing#triggerServiceDump(String,
+ * com.android.internal.inputmethod.ImeTracing.ServiceDumper, byte[])} needs to be triggered
+ * with the given parameters.
+ *
+ * @param where {@code where} parameter to be passed.
+ * @param icProto {@code icProto} parameter to be passed.
+ */
+ default void triggerServiceDump(String where, @Nullable byte[] icProto) {
+ }
+}
diff --git a/core/java/android/inputmethodservice/RemoteInputConnection.java b/core/java/android/inputmethodservice/RemoteInputConnection.java
index 9ab8ab6..4fa98be 100644
--- a/core/java/android/inputmethodservice/RemoteInputConnection.java
+++ b/core/java/android/inputmethodservice/RemoteInputConnection.java
@@ -22,9 +22,6 @@
import android.annotation.Nullable;
import android.os.Bundle;
import android.os.Handler;
-import android.util.imetracing.ImeTracing;
-import android.util.imetracing.InputConnectionHelper;
-import android.util.proto.ProtoOutputStream;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
@@ -39,6 +36,8 @@
import com.android.internal.inputmethod.CancellationGroup;
import com.android.internal.inputmethod.Completable;
import com.android.internal.inputmethod.IInputContextInvoker;
+import com.android.internal.inputmethod.ImeTracing;
+import com.android.internal.inputmethod.InputConnectionProtoDumper;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethod;
@@ -53,7 +52,7 @@
private final IInputContextInvoker mInvoker;
@NonNull
- private final WeakReference<AbstractInputMethodService> mInputMethodService;
+ private final WeakReference<InputMethodServiceInternal> mInputMethodService;
@MissingMethodFlags
private final int mMissingMethods;
@@ -68,7 +67,7 @@
private final CancellationGroup mCancellationGroup;
RemoteInputConnection(
- @NonNull WeakReference<AbstractInputMethodService> inputMethodService,
+ @NonNull WeakReference<InputMethodServiceInternal> inputMethodService,
IInputContext inputContext, @MissingMethodFlags int missingMethods,
@NonNull CancellationGroup cancellationGroup) {
mInputMethodService = inputMethodService;
@@ -91,12 +90,11 @@
final CharSequence result = Completable.getResultOrNull(
value, TAG, "getTextAfterCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
- final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
- ProtoOutputStream icProto = InputConnectionHelper.buildGetTextAfterCursorProto(length,
+ final byte[] icProto = InputConnectionProtoDumper.buildGetTextAfterCursorProto(length,
flags, result);
- ImeTracing.getInstance().triggerServiceDump(TAG + "#getTextAfterCursor",
- inputMethodService, icProto);
+ inputMethodService.triggerServiceDump(TAG + "#getTextAfterCursor", icProto);
}
return result;
@@ -116,12 +114,11 @@
final CharSequence result = Completable.getResultOrNull(
value, TAG, "getTextBeforeCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
- final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
- ProtoOutputStream icProto = InputConnectionHelper.buildGetTextBeforeCursorProto(length,
+ final byte[] icProto = InputConnectionProtoDumper.buildGetTextBeforeCursorProto(length,
flags, result);
- ImeTracing.getInstance().triggerServiceDump(TAG + "#getTextBeforeCursor",
- inputMethodService, icProto);
+ inputMethodService.triggerServiceDump(TAG + "#getTextBeforeCursor", icProto);
}
return result;
@@ -141,12 +138,11 @@
final CharSequence result = Completable.getResultOrNull(
value, TAG, "getSelectedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
- final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
- ProtoOutputStream icProto = InputConnectionHelper.buildGetSelectedTextProto(flags,
+ final byte[] icProto = InputConnectionProtoDumper.buildGetSelectedTextProto(flags,
result);
- ImeTracing.getInstance().triggerServiceDump(TAG + "#getSelectedText",
- inputMethodService, icProto);
+ inputMethodService.triggerServiceDump(TAG + "#getSelectedText", icProto);
}
return result;
@@ -180,12 +176,11 @@
final SurroundingText result = Completable.getResultOrNull(
value, TAG, "getSurroundingText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
- final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
- ProtoOutputStream icProto = InputConnectionHelper.buildGetSurroundingTextProto(
+ final byte[] icProto = InputConnectionProtoDumper.buildGetSurroundingTextProto(
beforeLength, afterLength, flags, result);
- ImeTracing.getInstance().triggerServiceDump(TAG + "#getSurroundingText",
- inputMethodService, icProto);
+ inputMethodService.triggerServiceDump(TAG + "#getSurroundingText", icProto);
}
return result;
@@ -201,12 +196,11 @@
final int result = Completable.getResultOrZero(
value, TAG, "getCursorCapsMode()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
- final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
- ProtoOutputStream icProto = InputConnectionHelper.buildGetCursorCapsModeProto(
+ final byte[] icProto = InputConnectionProtoDumper.buildGetCursorCapsModeProto(
reqModes, result);
- ImeTracing.getInstance().triggerServiceDump(TAG + "#getCursorCapsMode",
- inputMethodService, icProto);
+ inputMethodService.triggerServiceDump(TAG + "#getCursorCapsMode", icProto);
}
return result;
@@ -222,12 +216,11 @@
final ExtractedText result = Completable.getResultOrNull(
value, TAG, "getExtractedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
- final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
- ProtoOutputStream icProto = InputConnectionHelper.buildGetExtractedTextProto(
+ final byte[] icProto = InputConnectionProtoDumper.buildGetExtractedTextProto(
request, flags, result);
- ImeTracing.getInstance().triggerServiceDump(TAG + "#getExtractedText",
- inputMethodService, icProto);
+ inputMethodService.triggerServiceDump(TAG + "#getExtractedText", icProto);
}
return result;
@@ -244,7 +237,7 @@
@AnyThread
private void notifyUserActionIfNecessary() {
- final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService == null) {
// This basically should not happen, because it's the the caller of this method.
return;
@@ -396,7 +389,7 @@
}
if ((flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
- final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
if (inputMethodService == null) {
// This basically should not happen, because it's the caller of this method.
return false;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index d7851a5..9cd8405 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -441,23 +441,30 @@
public static final int CUR_DEVELOPMENT = 10000;
/**
- * October 2008: The original, first, version of Android. Yay!
+ * The original, first, version of Android. Yay!
+ *
+ * <p>Released publicly as Android 1.0 in September 2008.
*/
public static final int BASE = 1;
/**
- * February 2009: First Android update, officially called 1.1.
+ * First Android update.
+ *
+ * <p>Released publicly as Android 1.1 in February 2009.
*/
public static final int BASE_1_1 = 2;
/**
- * May 2009: Android 1.5.
+ * C.
+ *
+ * <p>Released publicly as Android 1.5 in April 2009.
*/
public static final int CUPCAKE = 3;
/**
- * September 2009: Android 1.6.
+ * D.
*
+ * <p>Released publicly as Android 1.6 in September 2009.
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
@@ -481,8 +488,9 @@
public static final int DONUT = 4;
/**
- * November 2009: Android 2.0
+ * E.
*
+ * <p>Released publicly as Android 2.0 in October 2009.
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
@@ -501,23 +509,30 @@
public static final int ECLAIR = 5;
/**
- * December 2009: Android 2.0.1
+ * E incremental update.
+ *
+ * <p>Released publicly as Android 2.0.1 in December 2009.
*/
public static final int ECLAIR_0_1 = 6;
/**
- * January 2010: Android 2.1
+ * E MR1.
+ *
+ * <p>Released publicly as Android 2.1 in January 2010.
*/
public static final int ECLAIR_MR1 = 7;
/**
- * June 2010: Android 2.2
+ * F.
+ *
+ * <p>Released publicly as Android 2.2 in May 2010.
*/
public static final int FROYO = 8;
/**
- * November 2010: Android 2.3
+ * G.
*
+ * <p>Released publicly as Android 2.3 in December 2010.
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
@@ -528,13 +543,16 @@
public static final int GINGERBREAD = 9;
/**
- * February 2011: Android 2.3.3.
+ * G MR1.
+ *
+ * <p>Released publicly as Android 2.3.3 in February 2011.
*/
public static final int GINGERBREAD_MR1 = 10;
/**
- * February 2011: Android 3.0.
+ * H.
*
+ * <p>Released publicly as Android 3.0 in February 2011.
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
@@ -573,13 +591,16 @@
public static final int HONEYCOMB = 11;
/**
- * May 2011: Android 3.1.
+ * H MR1.
+ *
+ * <p>Released publicly as Android 3.1 in May 2011.
*/
public static final int HONEYCOMB_MR1 = 12;
/**
- * June 2011: Android 3.2.
+ * H MR2.
*
+ * <p>Released publicly as Android 3.2 in July 2011.
* <p>Update to Honeycomb MR1 to support 7 inch tablets, improve
* screen compatibility mode, etc.</p>
*
@@ -626,8 +647,9 @@
public static final int HONEYCOMB_MR2 = 13;
/**
- * October 2011: Android 4.0.
+ * I.
*
+ * <p>Released publicly as Android 4.0 in October 2011.
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
@@ -672,13 +694,16 @@
public static final int ICE_CREAM_SANDWICH = 14;
/**
- * December 2011: Android 4.0.3.
+ * I MR1.
+ *
+ * <p>Released publicly as Android 4.03 in December 2011.
*/
public static final int ICE_CREAM_SANDWICH_MR1 = 15;
/**
- * June 2012: Android 4.1.
+ * J.
*
+ * <p>Released publicly as Android 4.1 in July 2012.
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
@@ -720,8 +745,9 @@
public static final int JELLY_BEAN = 16;
/**
- * November 2012: Android 4.2, Moar jelly beans!
+ * J MR1.
*
+ * <p>Released publicly as Android 4.2 in November 2012.
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
@@ -740,13 +766,16 @@
public static final int JELLY_BEAN_MR1 = 17;
/**
- * July 2013: Android 4.3, the revenge of the beans.
+ * J MR2.
+ *
+ * <p>Released publicly as Android 4.3 in July 2013.
*/
public static final int JELLY_BEAN_MR2 = 18;
/**
- * October 2013: Android 4.4, KitKat, another tasty treat.
+ * K.
*
+ * <p>Released publicly as Android 4.4 in October 2013.
* <p>Applications targeting this or a later release will get these
* new changes in behavior. For more information about this release, see the
* <a href="/about/versions/kitkat/">Android KitKat overview</a>.</p>
@@ -778,8 +807,9 @@
public static final int KITKAT = 19;
/**
- * June 2014: Android 4.4W. KitKat for watches, snacks on the run.
+ * K for watches.
*
+ * <p>Released publicly as Android 4.4W in June 2014.
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
@@ -796,8 +826,9 @@
public static final int L = 21;
/**
- * November 2014: Lollipop. A flat one with beautiful shadows. But still tasty.
+ * L.
*
+ * <p>Released publicly as Android 5.0 in November 2014.
* <p>Applications targeting this or a later release will get these
* new changes in behavior. For more information about this release, see the
* <a href="/about/versions/lollipop/">Android Lollipop overview</a>.</p>
@@ -828,15 +859,18 @@
public static final int LOLLIPOP = 21;
/**
- * March 2015: Lollipop with an extra sugar coating on the outside!
- * For more information about this release, see the
+ * L MR1.
+ *
+ * <p>Released publicly as Android 5.1 in March 2015.
+ * <p>For more information about this release, see the
* <a href="/about/versions/android-5.1">Android 5.1 APIs</a>.
*/
public static final int LOLLIPOP_MR1 = 22;
/**
- * M is for Marshmallow!
+ * M.
*
+ * <p>Released publicly as Android 6.0 in October 2015.
* <p>Applications targeting this or a later release will get these
* new changes in behavior. For more information about this release, see the
* <a href="/about/versions/marshmallow/">Android 6.0 Marshmallow overview</a>.</p>
@@ -867,8 +901,9 @@
public static final int M = 23;
/**
- * N is for Nougat.
+ * N.
*
+ * <p>Released publicly as Android 7.0 in August 2016.
* <p>Applications targeting this or a later release will get these
* new changes in behavior. For more information about this release, see
* the <a href="/about/versions/nougat/">Android Nougat overview</a>.</p>
@@ -921,7 +956,10 @@
public static final int N = 24;
/**
- * N MR1: Nougat++. For more information about this release, see
+ * N MR1.
+ *
+ * <p>Released publicly as Android 7.1 in October 2016.
+ * <p>For more information about this release, see
* <a href="/about/versions/nougat/android-7.1">Android 7.1 for
* Developers</a>.
*/
@@ -930,6 +968,7 @@
/**
* O.
*
+ * <p>Released publicly as Android 8.0 in August 2017.
* <p>Applications targeting this or a later release will get these
* new changes in behavior. For more information about this release, see
* the <a href="/about/versions/oreo/">Android Oreo overview</a>.</p>
@@ -1020,6 +1059,7 @@
/**
* O MR1.
*
+ * <p>Released publicly as Android 8.1 in December 2017.
* <p>Applications targeting this or a later release will get these
* new changes in behavior. For more information about this release, see
* <a href="/about/versions/oreo/android-8.1">Android 8.1 features and
@@ -1037,6 +1077,7 @@
/**
* P.
*
+ * <p>Released publicly as Android 9 in August 2018.
* <p>Applications targeting this or a later release will get these
* new changes in behavior. For more information about this release, see the
* <a href="/about/versions/pie/">Android 9 Pie overview</a>.</p>
@@ -1054,6 +1095,7 @@
/**
* Q.
*
+ * <p>Released publicly as Android 10 in September 2019.
* <p>Applications targeting this or a later release will get these new changes in behavior.
* For more information about this release, see the
* <a href="/about/versions/10">Android 10 overview</a>.</p>
@@ -1069,6 +1111,7 @@
/**
* R.
*
+ * <p>Released publicly as Android 11 in September 2020.
* <p>Applications targeting this or a later release will get these new changes in behavior.
* For more information about this release, see the
* <a href="/about/versions/11">Android 11 overview</a>.</p>
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index f4c8d48..880d03a 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -794,7 +794,7 @@
}
/**
- * Create a new property with the the provided name and value in the provided namespace, or
+ * Create a new property with the provided name and value in the provided namespace, or
* update the value of such a property if it already exists. The same name can exist in multiple
* namespaces and might have different values in any or all namespaces.
* <p>
@@ -844,6 +844,22 @@
}
/**
+ * Delete a property with the provided name and value in the provided namespace
+ *
+ * @param namespace The namespace containing the property to create or update.
+ * @param name The name of the property to create or update.
+ * @return True if the property was deleted or it did not exist in the first place.
+ * False if the storage implementation throws errors.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(WRITE_DEVICE_CONFIG)
+ public static boolean deleteProperty(@NonNull String namespace, @NonNull String name) {
+ ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
+ return Settings.Config.deleteString(contentResolver, namespace, name);
+ }
+
+ /**
* Reset properties to their default values by removing the underlying values.
* <p>
* The method accepts an optional namespace parameter. If provided, only properties set within
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d2588a3..6c1bf8e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2770,6 +2770,7 @@
// for the fast path of retrieving settings.
private final String mCallGetCommand;
private final String mCallSetCommand;
+ private final String mCallDeleteCommand;
private final String mCallListCommand;
private final String mCallSetAllCommand;
@@ -2781,17 +2782,19 @@
private GenerationTracker mGenerationTracker;
<T extends NameValueTable> NameValueCache(Uri uri, String getCommand,
- String setCommand, ContentProviderHolder providerHolder, Class<T> callerClass) {
- this(uri, getCommand, setCommand, null, null, providerHolder,
+ String setCommand, String deleteCommand, ContentProviderHolder providerHolder,
+ Class<T> callerClass) {
+ this(uri, getCommand, setCommand, deleteCommand, null, null, providerHolder,
callerClass);
}
private <T extends NameValueTable> NameValueCache(Uri uri, String getCommand,
- String setCommand, String listCommand, String setAllCommand,
+ String setCommand, String deleteCommand, String listCommand, String setAllCommand,
ContentProviderHolder providerHolder, Class<T> callerClass) {
mUri = uri;
mCallGetCommand = getCommand;
mCallSetCommand = setCommand;
+ mCallDeleteCommand = deleteCommand;
mCallListCommand = listCommand;
mCallSetAllCommand = setAllCommand;
mProviderHolder = providerHolder;
@@ -2849,6 +2852,20 @@
}
}
+ public boolean deleteStringForUser(ContentResolver cr, String name, final int userHandle) {
+ try {
+ Bundle arg = new Bundle();
+ arg.putInt(CALL_METHOD_USER_KEY, userHandle);
+ IContentProvider cp = mProviderHolder.getProvider(cr);
+ cp.call(cr.getAttributionSource(),
+ mProviderHolder.mUri.getAuthority(), mCallDeleteCommand, name, arg);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Can't delete key " + name + " in " + mUri, e);
+ return false;
+ }
+ return true;
+ }
+
@UnsupportedAppUsage
public String getStringForUser(ContentResolver cr, String name, final int userHandle) {
// Check if the target settings key is readable. Reject if the caller is not system and
@@ -3311,6 +3328,7 @@
CONTENT_URI,
CALL_METHOD_GET_SYSTEM,
CALL_METHOD_PUT_SYSTEM,
+ CALL_METHOD_DELETE_SYSTEM,
sProviderHolder,
System.class);
@@ -5631,6 +5649,7 @@
CONTENT_URI,
CALL_METHOD_GET_SECURE,
CALL_METHOD_PUT_SECURE,
+ CALL_METHOD_DELETE_SECURE,
sProviderHolder,
Secure.class);
@@ -15021,6 +15040,7 @@
CONTENT_URI,
CALL_METHOD_GET_GLOBAL,
CALL_METHOD_PUT_GLOBAL,
+ CALL_METHOD_DELETE_GLOBAL,
sProviderHolder,
Global.class);
@@ -16692,6 +16712,7 @@
DeviceConfig.CONTENT_URI,
CALL_METHOD_GET_CONFIG,
CALL_METHOD_PUT_CONFIG,
+ CALL_METHOD_DELETE_CONFIG,
CALL_METHOD_LIST_CONFIG,
CALL_METHOD_SET_ALL_CONFIG,
sProviderHolder,
@@ -16801,6 +16822,26 @@
}
/**
+ * Delete a name/value pair from the database for the specified namespace.
+ *
+ * @param resolver to access the database with.
+ * @param namespace to delete the name/value pair from.
+ * @param name to delete.
+ * @return true if the value was deleted, false on database errors. If the name/value pair
+ * did not exist, return True.
+ *
+ * @see #resetToDefaults(ContentResolver, int, String)
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
+ static boolean deleteString(@NonNull ContentResolver resolver, @NonNull String namespace,
+ @NonNull String name) {
+ return sNameValueCache.deleteStringForUser(resolver,
+ createCompositeName(namespace, name), resolver.getUserId());
+ }
+
+ /**
* Reset the values to their defaults.
* <p>
* The method accepts an optional prefix parameter. If provided, only pairs with a name that
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index ff69281..ee8353a 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -1969,7 +1969,17 @@
}
public boolean isAutomaticActive() {
- return enabled && !snoozing && pkg != null && isTrueOrUnknown();
+ return enabled && !snoozing && getPkg() != null && isTrueOrUnknown();
+ }
+
+ public String getPkg() {
+ return !TextUtils.isEmpty(pkg)
+ ? pkg
+ : (component != null)
+ ? component.getPackageName()
+ : (configurationActivity != null)
+ ? configurationActivity.getPackageName()
+ : null;
}
public boolean isTrueOrUnknown() {
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 27bd6a3..d46265e 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -2014,7 +2014,7 @@
return mIndex;
}
- /**s
+ /**
* @return the total number of activities for which the assist data is
* being returned.
*/
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index f0ce325..0c04976 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -198,6 +198,7 @@
ApkSignatureSchemeV4Verifier.extractCertificates(apkPath);
Certificate[][] signerCerts = new Certificate[][]{vSigner.certs};
Signature[] signerSigs = convertToSignatures(signerCerts);
+ Signature[] pastSignerSigs = null;
if (verifyFull) {
Map<Integer, byte[]> nonstreamingDigests;
@@ -210,6 +211,15 @@
ApkSignatureSchemeV3Verifier.unsafeGetCertsWithoutVerification(apkPath);
nonstreamingDigests = v3Signer.contentDigests;
nonstreamingCerts = new Certificate[][]{v3Signer.certs};
+ if (v3Signer.por != null) {
+ // populate proof-of-rotation information
+ pastSignerSigs = new Signature[v3Signer.por.certs.size()];
+ for (int i = 0; i < pastSignerSigs.length; i++) {
+ pastSignerSigs[i] = new Signature(
+ v3Signer.por.certs.get(i).getEncoded());
+ pastSignerSigs[i].setFlags(v3Signer.por.flagsList.get(i));
+ }
+ }
} catch (SignatureNotFoundException e) {
try {
ApkSignatureSchemeV2Verifier.VerifiedSigner v2Signer =
@@ -250,7 +260,8 @@
}
return new SigningDetailsWithDigests(new SigningDetails(signerSigs,
- SignatureSchemeVersion.SIGNING_BLOCK_V4), vSigner.contentDigests);
+ SignatureSchemeVersion.SIGNING_BLOCK_V4, pastSignerSigs),
+ vSigner.contentDigests);
} catch (SignatureNotFoundException e) {
throw e;
} catch (Exception e) {
diff --git a/core/java/android/util/imetracing/OWNERS b/core/java/android/util/imetracing/OWNERS
deleted file mode 100644
index 885fd0a..0000000
--- a/core/java/android/util/imetracing/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-set noparent
-
-include /services/core/java/com/android/server/inputmethod/OWNERS
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 305cb97..f4539c2 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -814,9 +814,10 @@
* @param displayId The display associated with the window context
* @param options A bundle used to pass window-related options and choose the right DisplayArea
*
- * @return {@code true} if the WindowContext is attached to the DisplayArea successfully.
+ * @return the DisplayArea's {@link android.app.res.Configuration} if the WindowContext is
+ * attached to the DisplayArea successfully. {@code null}, otherwise.
*/
- boolean attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId,
+ Configuration attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId,
in Bundle options);
/**
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 6f915c9..1a9b34e 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -45,7 +45,6 @@
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
-import android.util.imetracing.ImeTracing;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsSourceConsumer.ShowResult;
import android.view.InsetsState.InternalInsetsType;
@@ -61,6 +60,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+import com.android.internal.inputmethod.ImeTracing;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index ee33541..bf9de39 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -36,13 +36,13 @@
import android.graphics.Insets;
import android.graphics.Rect;
import android.util.Log;
-import android.util.imetracing.ImeTracing;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets.Type.InsetsType;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.inputmethod.ImeTracing;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3bf8b52..dbaf327 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -151,7 +151,6 @@
import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.TypedValue;
-import android.util.imetracing.ImeTracing;
import android.util.proto.ProtoOutputStream;
import android.view.InputDevice.InputSourceClass;
import android.view.InsetsState.InternalInsetsType;
@@ -192,6 +191,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
+import com.android.internal.inputmethod.ImeTracing;
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.os.IResultReceiver;
import com.android.internal.os.SomeArgs;
@@ -1970,22 +1970,23 @@
return mBoundsLayer;
}
- Surface getOrCreateBLASTSurface(int width, int height,
- @Nullable WindowManager.LayoutParams params) {
+ Surface getOrCreateBLASTSurface() {
if (!mSurfaceControl.isValid()) {
return null;
}
- int format = params == null ? PixelFormat.TRANSLUCENT : params.format;
Surface ret = null;
if (mBlastBufferQueue == null) {
- mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl, width, height,
- format);
+ mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
+ mSurfaceSize.x, mSurfaceSize.y,
+ mWindowAttributes.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(mSurfaceControl,
+ mSurfaceSize.x, mSurfaceSize.y,
+ mWindowAttributes.format);
}
return ret;
@@ -7799,8 +7800,7 @@
if (!useBLAST()) {
mSurface.copyFrom(mSurfaceControl);
} else {
- final Surface blastSurface = getOrCreateBLASTSurface(mSurfaceSize.x, mSurfaceSize.y,
- params);
+ final Surface blastSurface = getOrCreateBLASTSurface();
// If blastSurface == null that means it hasn't changed since the last time we
// called. In this situation, avoid calling transferFrom as we would then
// inc the generation ID and cause EGL resources to be recreated.
@@ -9180,26 +9180,15 @@
return;
}
- final long eventSourceNodeId = event.getSourceNodeId();
- final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
-
- // Only change types that may affect the bounds of the focused virtual view should run
- // the update bounds logic after this if block.
+ // We only care about change types that may affect the bounds of the
+ // focused virtual view.
final int changes = event.getContentChangeTypes();
if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
&& changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
- // Now the changes(text, content description, state description) are local to this node.
- // If the focused virtual view changed, we need to update the
- // mAccessibilityFocusedVirtualView, otherwise A11y services will get stale value.
- if (eventSourceNodeId == focusedSourceNodeId) {
- int focusedChildId =
- AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
- mAccessibilityFocusedVirtualView =
- provider.createAccessibilityNodeInfo(focusedChildId);
- }
return;
}
+ final long eventSourceNodeId = event.getSourceNodeId();
final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
// Search up the tree for subtree containment.
@@ -9223,6 +9212,7 @@
return;
}
+ final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
// Refresh the node for the focused virtual view.
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 42d77cd..110bd33 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -18,7 +18,6 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
-import static android.util.imetracing.ImeTracing.PROTO_ARG;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.DISPLAY_ID;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.EDITOR_INFO;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_INSETS_SOURCE_CONSUMER;
@@ -73,7 +72,6 @@
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.SparseArray;
-import android.util.imetracing.ImeTracing;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.ImeFocusController;
@@ -88,6 +86,7 @@
import android.view.autofill.AutofillManager;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.inputmethod.ImeTracing;
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
import com.android.internal.inputmethod.SoftInputShowHideReason;
@@ -3192,7 +3191,7 @@
}
for (String arg : args) {
- if (arg.equals(PROTO_ARG)) {
+ if (arg.equals(ImeTracing.PROTO_ARG)) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
dumpDebug(proto, null /* icProto */);
proto.flush();
@@ -3211,7 +3210,7 @@
* @hide
*/
@GuardedBy("mH")
- public void dumpDebug(ProtoOutputStream proto, ProtoOutputStream icProto) {
+ public void dumpDebug(ProtoOutputStream proto, @Nullable byte[] icProto) {
if (mCurrentInputMethodSession == null) {
return;
}
@@ -3237,7 +3236,7 @@
mServedInputConnectionWrapper.dumpDebug(proto, INPUT_CONNECTION);
}
if (icProto != null) {
- proto.write(INPUT_CONNECTION_CALL, icProto.getBytes());
+ proto.write(INPUT_CONNECTION_CALL, icProto);
}
}
}
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 9c12850..3df09c2 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -740,8 +740,22 @@
}
}
- private void onTimeChanged() {
- Instant now = mClock.instant();
+ /**
+ * Return the current Instant to be used for drawing the clockface. Protected to allow
+ * subclasses to override this to show a different time from the system clock.
+ *
+ * @return the Instant to be shown on the clockface
+ * @hide
+ */
+ protected Instant now() {
+ return mClock.instant();
+ }
+
+ /**
+ * @hide
+ */
+ protected void onTimeChanged() {
+ Instant now = now();
onTimeChanged(now.atZone(mClock.getZone()).toLocalTime(), now.toEpochMilli());
}
@@ -789,7 +803,7 @@
return;
}
- Instant now = mClock.instant();
+ Instant now = now();
ZonedDateTime zonedDateTime = now.atZone(mClock.getZone());
LocalTime localTime = zonedDateTime.toLocalTime();
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 472e3e7..c110ab9 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -365,6 +365,10 @@
mDuration = PULL_TIME;
mPullDistance += deltaDistance;
+ if (edgeEffectBehavior == TYPE_STRETCH) {
+ // Don't allow stretch beyond 1
+ mPullDistance = Math.min(1f, mPullDistance);
+ }
mDistance = Math.max(0f, mPullDistance);
mVelocity = 0;
@@ -783,6 +787,10 @@
+ mDampedFreq * sinCoeff * Math.cos(mDampedFreq * deltaT));
mDistance = (float) distance / mHeight;
mVelocity = (float) velocity;
+ if (mDistance > 1f) {
+ mDistance = 1f;
+ mVelocity = 0f;
+ }
if (isAtEquilibrium()) {
mDistance = 0;
mVelocity = 0;
diff --git a/core/java/android/window/ITaskFragmentOrganizer.aidl b/core/java/android/window/ITaskFragmentOrganizer.aidl
index 0bfc254..5eb432e 100644
--- a/core/java/android/window/ITaskFragmentOrganizer.aidl
+++ b/core/java/android/window/ITaskFragmentOrganizer.aidl
@@ -17,6 +17,7 @@
package android.window;
import android.content.res.Configuration;
+import android.os.Bundle;
import android.os.IBinder;
import android.window.TaskFragmentAppearedInfo;
import android.window.TaskFragmentInfo;
@@ -37,4 +38,15 @@
* bounds.
*/
void onTaskFragmentParentInfoChanged(in IBinder fragmentToken, in Configuration parentConfig);
+
+ /**
+ * Called when the {@link WindowContainerTransaction} created with
+ * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
+ *
+ * @param errorCallbackToken Token set through {@link
+ * WindowContainerTransaction#setErrorCallbackToken(IBinder)}
+ * @param exceptionBundle Bundle containing the exception. Should be created with
+ * {@link TaskFragmentOrganizer#putExceptionInBundle}.
+ */
+ void onTaskFragmentError(in IBinder errorCallbackToken, in Bundle exceptionBundle);
}
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java
index f864c91..6d4a2f1 100644
--- a/core/java/android/window/TaskFragmentInfo.java
+++ b/core/java/android/window/TaskFragmentInfo.java
@@ -25,6 +25,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Stores information about a particular TaskFragment.
* @hide
@@ -50,9 +53,16 @@
/** Whether this TaskFragment is visible on the window hierarchy. */
private final boolean mIsVisible;
+ /**
+ * List of Activity tokens that are children of this TaskFragment. It only contains Activities
+ * that belong to the organizer process for security.
+ */
+ private final List<IBinder> mActivities = new ArrayList<>();
+
public TaskFragmentInfo(
@NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
- @NonNull Configuration configuration, boolean isEmpty, boolean isVisible) {
+ @NonNull Configuration configuration, boolean isEmpty, boolean isVisible,
+ List<IBinder> activities) {
if (fragmentToken == null) {
throw new IllegalArgumentException("Invalid TaskFragmentInfo.");
}
@@ -61,6 +71,7 @@
mConfiguration.setTo(configuration);
mIsEmpty = isEmpty;
mIsVisible = isVisible;
+ mActivities.addAll(activities);
}
public IBinder getFragmentToken() {
@@ -83,6 +94,10 @@
return mIsVisible;
}
+ public List<IBinder> getActivities() {
+ return mActivities;
+ }
+
@WindowingMode
public int getWindowingMode() {
return mConfiguration.windowConfiguration.getWindowingMode();
@@ -101,7 +116,8 @@
&& mToken.equals(that.mToken)
&& mIsEmpty == that.mIsEmpty
&& mIsVisible == that.mIsVisible
- && getWindowingMode() == that.getWindowingMode();
+ && getWindowingMode() == that.getWindowingMode()
+ && mActivities.equals(that.mActivities);
}
private TaskFragmentInfo(Parcel in) {
@@ -110,6 +126,7 @@
mConfiguration.readFromParcel(in);
mIsEmpty = in.readBoolean();
mIsVisible = in.readBoolean();
+ in.readBinderList(mActivities);
}
@Override
@@ -119,6 +136,7 @@
mConfiguration.writeToParcel(dest, flags);
dest.writeBoolean(mIsEmpty);
dest.writeBoolean(mIsVisible);
+ dest.writeBinderList(mActivities);
}
@NonNull
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index 51722cc..3b4d4e5 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -19,6 +19,7 @@
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.content.res.Configuration;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -31,6 +32,21 @@
public class TaskFragmentOrganizer extends WindowOrganizer {
/**
+ * Key to the exception in {@link Bundle} in {@link ITaskFragmentOrganizer#onTaskFragmentError}.
+ */
+ private static final String KEY_ERROR_CALLBACK_EXCEPTION = "fragment_exception";
+
+ /**
+ * Creates a {@link Bundle} with an exception that can be passed to
+ * {@link ITaskFragmentOrganizer#onTaskFragmentError}.
+ */
+ public static Bundle putExceptionInBundle(@NonNull Throwable exception) {
+ final Bundle exceptionBundle = new Bundle();
+ exceptionBundle.putSerializable(KEY_ERROR_CALLBACK_EXCEPTION, exception);
+ return exceptionBundle;
+ }
+
+ /**
* Callbacks from WM Core are posted on this executor.
*/
private final Executor mExecutor;
@@ -93,6 +109,17 @@
public void onTaskFragmentParentInfoChanged(
@NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {}
+ /**
+ * Called when the {@link WindowContainerTransaction} created with
+ * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
+ *
+ * @param errorCallbackToken token set in
+ * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)}
+ * @param exception exception from the server side.
+ */
+ public void onTaskFragmentError(
+ @NonNull IBinder errorCallbackToken, @NonNull Throwable exception) {}
+
private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() {
@Override
public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentInfo) {
@@ -119,8 +146,20 @@
() -> TaskFragmentOrganizer.this.onTaskFragmentParentInfoChanged(
fragmentToken, parentConfig));
}
+
+ @Override
+ public void onTaskFragmentError(
+ @NonNull IBinder errorCallbackToken, @NonNull Bundle exceptionBundle) {
+ mExecutor.execute(() -> TaskFragmentOrganizer.this.onTaskFragmentError(
+ errorCallbackToken,
+ (Throwable) exceptionBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION)));
+ }
};
+ public ITaskFragmentOrganizer getIOrganizer() {
+ return mInterface;
+ }
+
private ITaskFragmentOrganizerController getController() {
try {
return getWindowOrganizerController().getTaskFragmentOrganizerController();
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 8c3dc2e..9c512ad 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -49,11 +49,15 @@
// Flat list because re-order operations are order-dependent
private final ArrayList<HierarchyOp> mHierarchyOps = new ArrayList<>();
+ @Nullable
+ private IBinder mErrorCallbackToken;
+
public WindowContainerTransaction() {}
private WindowContainerTransaction(Parcel in) {
in.readMap(mChanges, null /* loader */);
in.readList(mHierarchyOps, null /* loader */);
+ mErrorCallbackToken = in.readStrongBinder();
}
private Change getOrCreateChange(IBinder token) {
@@ -476,6 +480,23 @@
}
/**
+ * When this {@link WindowContainerTransaction} failed to finish on the server side, it will
+ * trigger callback with this {@param errorCallbackToken}.
+ * @param errorCallbackToken client provided token that will be passed back as parameter in
+ * the callback if there is an error on the server side.
+ * @see ITaskFragmentOrganizer#onTaskFragmentError
+ * @hide
+ */
+ @NonNull
+ public WindowContainerTransaction setErrorCallbackToken(@NonNull IBinder errorCallbackToken) {
+ if (mErrorCallbackToken != null) {
+ throw new IllegalStateException("Can't set multiple error token for one transaction.");
+ }
+ mErrorCallbackToken = errorCallbackToken;
+ return this;
+ }
+
+ /**
* Merges another WCT into this one.
* @param transfer When true, this will transfer everything from other potentially leaving
* other in an unusable state. When false, other is left alone, but
@@ -496,6 +517,13 @@
mHierarchyOps.add(transfer ? other.mHierarchyOps.get(i)
: new HierarchyOp(other.mHierarchyOps.get(i)));
}
+ if (mErrorCallbackToken != null && other.mErrorCallbackToken != null && mErrorCallbackToken
+ != other.mErrorCallbackToken) {
+ throw new IllegalArgumentException("Can't merge two WCT with different error token");
+ }
+ mErrorCallbackToken = mErrorCallbackToken != null
+ ? mErrorCallbackToken
+ : other.mErrorCallbackToken;
}
/** @hide */
@@ -513,11 +541,17 @@
return mHierarchyOps;
}
+ /** @hide */
+ @Nullable
+ public IBinder getErrorCallbackToken() {
+ return mErrorCallbackToken;
+ }
+
@Override
@NonNull
public String toString() {
return "WindowContainerTransaction { changes = " + mChanges + " hops = " + mHierarchyOps
- + " }";
+ + " errorCallbackToken=" + mErrorCallbackToken + " }";
}
@Override
@@ -525,6 +559,7 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeMap(mChanges);
dest.writeList(mHierarchyOps);
+ dest.writeStrongBinder(mErrorCallbackToken);
}
@Override
diff --git a/core/java/android/window/WindowContext.java b/core/java/android/window/WindowContext.java
index 69d7b4c..5d40085 100644
--- a/core/java/android/window/WindowContext.java
+++ b/core/java/android/window/WindowContext.java
@@ -26,7 +26,6 @@
import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.os.Bundle;
-import android.os.IBinder;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
@@ -73,7 +72,7 @@
mType = type;
mOptions = options;
mWindowManager = createWindowContextWindowManager(this);
- IBinder token = getWindowContextToken();
+ WindowTokenClient token = (WindowTokenClient) getWindowContextToken();
mController = new WindowContextController(token);
Reference.reachabilityFence(this);
diff --git a/core/java/android/window/WindowContextController.java b/core/java/android/window/WindowContextController.java
index d84f571..5aa6233 100644
--- a/core/java/android/window/WindowContextController.java
+++ b/core/java/android/window/WindowContextController.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -46,7 +47,7 @@
@VisibleForTesting
public boolean mAttachedToDisplayArea;
@NonNull
- private final IBinder mToken;
+ private final WindowTokenClient mToken;
/**
* Window Context Controller constructor
@@ -54,14 +55,13 @@
* @param token The token used to attach to a window manager node. It is usually from
* {@link Context#getWindowContextToken()}.
*/
- public WindowContextController(@NonNull IBinder token) {
- mToken = token;
- mWms = WindowManagerGlobal.getWindowManagerService();
+ public WindowContextController(@NonNull WindowTokenClient token) {
+ this(token, WindowManagerGlobal.getWindowManagerService());
}
/** Used for test only. DO NOT USE it in production code. */
@VisibleForTesting
- public WindowContextController(@NonNull IBinder token, IWindowManager mockWms) {
+ public WindowContextController(@NonNull WindowTokenClient token, IWindowManager mockWms) {
mToken = token;
mWms = mockWms;
}
@@ -81,8 +81,15 @@
+ "a DisplayArea once.");
}
try {
- mAttachedToDisplayArea = mWms.attachWindowContextToDisplayArea(mToken, type, displayId,
- options);
+ final Configuration configuration = mWms.attachWindowContextToDisplayArea(mToken, type,
+ displayId, options);
+ if (configuration != null) {
+ mAttachedToDisplayArea = true;
+ // Send the DisplayArea's configuration to WindowContext directly instead of
+ // waiting for dispatching from WMS.
+ mToken.onConfigurationChanged(configuration, displayId,
+ false /* shouldReportConfigChange */);
+ }
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index c32a268..284b4b9 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -29,9 +29,12 @@
import android.inputmethodservice.AbstractInputMethodService;
import android.os.Build;
import android.os.Bundle;
+import android.os.Debug;
import android.os.IBinder;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.lang.ref.WeakReference;
/**
@@ -65,7 +68,7 @@
* can only attach one {@link Context}.
* <p>This method must be called before invoking
* {@link android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int,
- * Bundle, boolean)}.<p/>
+ * Bundle)}.<p/>
*
* @param context context to be attached
* @throws IllegalStateException if attached context has already existed.
@@ -80,8 +83,26 @@
&& context instanceof AbstractInputMethodService;
}
+ /**
+ * Called when {@link Configuration} updates from the server side receive.
+ *
+ * @param newConfig the updated {@link Configuration}
+ * @param newDisplayId the updated {@link android.view.Display} ID
+ */
@Override
public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
+ onConfigurationChanged(newConfig, newDisplayId, true /* shouldReportConfigChange */);
+ }
+
+ /**
+ * Called when {@link Configuration} updates from the server side receive.
+ *
+ * Similar to {@link #onConfigurationChanged(Configuration, int)}, but adds a flag to control
+ * whether to dispatch configuration update or not.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public void onConfigurationChanged(Configuration newConfig, int newDisplayId,
+ boolean shouldReportConfigChange) {
final Context context = mContextRef.get();
if (context == null) {
return;
@@ -102,9 +123,10 @@
// TODO(ag/9789103): update resource manager logic to track non-activity tokens
mResourcesManager.updateResourcesForActivity(this, newConfig, newDisplayId);
- if (context instanceof WindowContext) {
+ if (shouldReportConfigChange && context instanceof WindowContext) {
+ final WindowContext windowContext = (WindowContext) context;
ActivityThread.currentActivityThread().getHandler().post(
- () -> ((WindowContext) context).dispatchConfigurationChanged(newConfig));
+ () -> windowContext.dispatchConfigurationChanged(newConfig));
}
// Dispatch onConfigurationChanged only if there's a significant public change to
@@ -115,17 +137,24 @@
? new SizeConfigurationBuckets(sizeConfigurations) : null;
final int diff = diffPublicWithSizeBuckets(mConfiguration, newConfig, buckets);
- if (context instanceof WindowProviderService && diff != 0) {
- ActivityThread.currentActivityThread().getHandler().post(() ->
- ((WindowProviderService) context).onConfigurationChanged(newConfig));
+ if (shouldReportConfigChange && diff != 0
+ && context instanceof WindowProviderService) {
+ final WindowProviderService windowProviderService = (WindowProviderService) context;
+ ActivityThread.currentActivityThread().getHandler().post(
+ () -> windowProviderService.onConfigurationChanged(newConfig));
}
freeTextLayoutCachesIfNeeded(diff);
- if (diff == 0 && mShouldDumpConfigForIme) {
- Log.d(TAG, "Configuration not dispatch to IME because configuration has no "
- + " public difference with updated config. "
- + " Current config=" + context.getResources().getConfiguration()
- + ", reported config=" + mConfiguration
- + ", updated config=" + newConfig);
+ if (mShouldDumpConfigForIme) {
+ if (!shouldReportConfigChange) {
+ Log.d(TAG, "Only apply configuration update to Resources because "
+ + "shouldReportConfigChange is false.\n" + Debug.getCallers(5));
+ } else if (diff == 0) {
+ Log.d(TAG, "Configuration not dispatch to IME because configuration has no "
+ + " public difference with updated config. "
+ + " Current config=" + context.getResources().getConfiguration()
+ + ", reported config=" + mConfiguration
+ + ", updated config=" + newConfig);
+ }
}
mConfiguration.setTo(newConfig);
}
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 986bbc8..b7f6a61 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -16,9 +16,9 @@
package com.android.internal.app;
+import static android.graphics.PixelFormat.TRANSLUCENT;
+
import android.animation.ObjectAnimator;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.ActionBar;
import android.app.Activity;
import android.content.ActivityNotFoundException;
@@ -26,22 +26,21 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.ColorFilter;
-import android.graphics.LinearGradient;
import android.graphics.Paint;
-import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.provider.Settings;
-import android.util.AttributeSet;
+import android.util.DisplayMetrics;
import android.util.Log;
+import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
-import android.view.animation.PathInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.OvershootInterpolator;
+import android.widget.AnalogClock;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -49,17 +48,22 @@
import org.json.JSONObject;
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+
/**
* @hide
*/
public class PlatLogoActivity extends Activity {
- private static final boolean WRITE_SETTINGS = true;
+ private static final String TAG = "PlatLogoActivity";
- private static final String R_EGG_UNLOCK_SETTING = "egg_mode_r";
+ private static final String S_EGG_UNLOCK_SETTING = "egg_mode_s";
- private static final int UNLOCK_TRIES = 3;
-
- BigDialView mDialView;
+ private SettableAnalogClock mClock;
+ private ImageView mLogo;
+ private BubblesDrawable mBg;
@Override
protected void onPause() {
@@ -69,42 +73,81 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- final float dp = getResources().getDisplayMetrics().density;
- getWindow().getDecorView().setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
getWindow().setNavigationBarColor(0);
getWindow().setStatusBarColor(0);
final ActionBar ab = getActionBar();
if (ab != null) ab.hide();
- mDialView = new BigDialView(this, null);
- if (Settings.System.getLong(getContentResolver(),
- R_EGG_UNLOCK_SETTING, 0) == 0) {
- mDialView.setUnlockTries(UNLOCK_TRIES);
- } else {
- mDialView.setUnlockTries(0);
- }
-
final FrameLayout layout = new FrameLayout(this);
- layout.setBackgroundColor(0xFFFF0000);
- layout.addView(mDialView, FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.MATCH_PARENT);
+
+ mClock = new SettableAnalogClock(this);
+
+ final DisplayMetrics dm = getResources().getDisplayMetrics();
+ final float dp = dm.density;
+ final int minSide = Math.min(dm.widthPixels, dm.heightPixels);
+ final int widgetSize = (int) (minSide * 0.75);
+ final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(widgetSize, widgetSize);
+ lp.gravity = Gravity.CENTER;
+ layout.addView(mClock, lp);
+
+ mLogo = new ImageView(this);
+ mLogo.setVisibility(View.GONE);
+ mLogo.setImageResource(R.drawable.platlogo);
+ layout.addView(mLogo, lp);
+
+ mBg = new BubblesDrawable();
+ mBg.setLevel(0);
+ mBg.avoid = widgetSize / 2;
+ mBg.padding = 0.5f * dp;
+ mBg.minR = 1 * dp;
+ layout.setBackground(mBg);
+
setContentView(layout);
}
+ private boolean shouldWriteSettings() {
+ return getPackageName().equals("android");
+ }
+
private void launchNextStage(boolean locked) {
+ mClock.animate()
+ .alpha(0f).scaleX(0.5f).scaleY(0.5f)
+ .withEndAction(() -> mClock.setVisibility(View.GONE))
+ .start();
+
+ mLogo.setAlpha(0f);
+ mLogo.setScaleX(0.5f);
+ mLogo.setScaleY(0.5f);
+ mLogo.setVisibility(View.VISIBLE);
+ mLogo.animate()
+ .alpha(1f)
+ .scaleX(1f)
+ .scaleY(1f)
+ .setInterpolator(new OvershootInterpolator())
+ .start();
+
+ mLogo.postDelayed(() -> {
+ final ObjectAnimator anim = ObjectAnimator.ofInt(mBg, "level", 0, 10000);
+ anim.setInterpolator(new DecelerateInterpolator(1f));
+ anim.start();
+ },
+ 500
+ );
+
final ContentResolver cr = getContentResolver();
try {
- if (WRITE_SETTINGS) {
+ if (shouldWriteSettings()) {
+ Log.v(TAG, "Saving egg unlock=" + locked);
+ syncTouchPressure();
Settings.System.putLong(cr,
- R_EGG_UNLOCK_SETTING,
+ S_EGG_UNLOCK_SETTING,
locked ? 0 : System.currentTimeMillis());
}
} catch (RuntimeException e) {
- Log.e("com.android.internal.app.PlatLogoActivity", "Can't write settings", e);
+ Log.e(TAG, "Can't write settings", e);
}
try {
@@ -151,7 +194,7 @@
if (mPressureMax >= 0) {
touchData.put("min", mPressureMin);
touchData.put("max", mPressureMax);
- if (WRITE_SETTINGS) {
+ if (shouldWriteSettings()) {
Settings.System.putString(getContentResolver(), TOUCH_STATS,
touchData.toString());
}
@@ -173,44 +216,35 @@
super.onStop();
}
- class BigDialView extends ImageView {
- private static final int COLOR_GREEN = 0xff3ddc84;
- private static final int COLOR_BLUE = 0xff4285f4;
- private static final int COLOR_NAVY = 0xff073042;
- private static final int COLOR_ORANGE = 0xfff86734;
- private static final int COLOR_CHARTREUSE = 0xffeff7cf;
- private static final int COLOR_LIGHTBLUE = 0xffd7effe;
+ /**
+ * Subclass of AnalogClock that allows the user to flip up the glass and adjust the hands.
+ */
+ public class SettableAnalogClock extends AnalogClock {
+ private int mOverrideHour = -1;
+ private int mOverrideMinute = -1;
+ private boolean mOverride = false;
- private static final int STEPS = 11;
- private static final float VALUE_CHANGE_MAX = 1f / STEPS;
-
- private BigDialDrawable mDialDrawable;
- private boolean mWasLocked;
-
- BigDialView(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- BigDialView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init();
- }
-
- BigDialView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- init();
- }
-
- private void init() {
- mDialDrawable = new BigDialDrawable();
- setImageDrawable(mDialDrawable);
+ public SettableAnalogClock(Context context) {
+ super(context);
}
@Override
- public void onDraw(Canvas c) {
- super.onDraw(c);
+ protected Instant now() {
+ final Instant realNow = super.now();
+ final ZoneId tz = Clock.systemDefaultZone().getZone();
+ final ZonedDateTime zdTime = realNow.atZone(tz);
+ if (mOverride) {
+ if (mOverrideHour < 0) {
+ mOverrideHour = zdTime.getHour();
+ }
+ return Clock.fixed(zdTime
+ .withHour(mOverrideHour)
+ .withMinute(mOverrideMinute)
+ .withSecond(0)
+ .toInstant(), tz).instant();
+ } else {
+ return realNow;
+ }
}
double toPositiveDegrees(double rad) {
@@ -221,226 +255,174 @@
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
- mWasLocked = mDialDrawable.isLocked();
+ mOverride = true;
// pass through
case MotionEvent.ACTION_MOVE:
+ measureTouchPressure(ev);
+
float x = ev.getX();
float y = ev.getY();
- float cx = (getLeft() + getRight()) / 2f;
- float cy = (getTop() + getBottom()) / 2f;
+ float cx = getWidth() / 2f;
+ float cy = getHeight() / 2f;
float angle = (float) toPositiveDegrees(Math.atan2(x - cx, y - cy));
- final int oldLevel = mDialDrawable.getUserLevel();
- mDialDrawable.touchAngle(angle);
- final int newLevel = mDialDrawable.getUserLevel();
- if (oldLevel != newLevel) {
- performHapticFeedback(newLevel == STEPS
- ? HapticFeedbackConstants.CONFIRM
- : HapticFeedbackConstants.CLOCK_TICK);
+
+ int minutes = (75 - (int) (angle / 6)) % 60;
+ int minuteDelta = minutes - mOverrideMinute;
+ if (minuteDelta != 0) {
+ if (Math.abs(minuteDelta) > 45 && mOverrideHour >= 0) {
+ int hourDelta = (minuteDelta < 0) ? 1 : -1;
+ mOverrideHour = (mOverrideHour + 24 + hourDelta) % 24;
+ }
+ mOverrideMinute = minutes;
+ if (mOverrideMinute == 0) {
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ if (getScaleX() == 1f) {
+ setScaleX(1.05f);
+ setScaleY(1.05f);
+ animate().scaleX(1f).scaleY(1f).setDuration(150).start();
+ }
+ } else {
+ performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
+ }
+
+ onTimeChanged();
+ postInvalidate();
}
+
return true;
case MotionEvent.ACTION_UP:
- if (mWasLocked != mDialDrawable.isLocked()) {
- launchNextStage(mDialDrawable.isLocked());
+ if (mOverrideMinute == 0 && (mOverrideHour % 12) == 0) {
+ Log.v(TAG, "12:00 let's gooooo");
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ launchNextStage(false);
}
return true;
}
return false;
}
+ }
+
+ static class Bubble {
+ public float x, y, r;
+ public int color;
+ }
+
+ class BubblesDrawable extends Drawable {
+ private static final int MAX_BUBBS = 2000;
+
+ private final int[] mColorIds = {
+ android.R.color.system_accent1_400,
+ android.R.color.system_accent1_500,
+ android.R.color.system_accent1_600,
+
+ android.R.color.system_accent2_400,
+ android.R.color.system_accent2_500,
+ android.R.color.system_accent2_600,
+ };
+
+ private int[] mColors = new int[mColorIds.length];
+
+ private final Bubble[] mBubbs = new Bubble[MAX_BUBBS];
+ private int mNumBubbs;
+
+ private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ public float avoid = 0f;
+ public float padding = 0f;
+ public float minR = 0f;
+
+ BubblesDrawable() {
+ for (int i = 0; i < mColorIds.length; i++) {
+ mColors[i] = getColor(mColorIds[i]);
+ }
+ for (int j = 0; j < mBubbs.length; j++) {
+ mBubbs[j] = new Bubble();
+ }
+ }
@Override
- public boolean performClick() {
- if (mDialDrawable.getUserLevel() < STEPS - 1) {
- mDialDrawable.setUserLevel(mDialDrawable.getUserLevel() + 1);
- performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
+ public void draw(Canvas canvas) {
+ final float f = getLevel() / 10000f;
+ mPaint.setStyle(Paint.Style.FILL);
+ int drawn = 0;
+ for (int j = 0; j < mNumBubbs; j++) {
+ if (mBubbs[j].color == 0 || mBubbs[j].r == 0) continue;
+ mPaint.setColor(mBubbs[j].color);
+ canvas.drawCircle(mBubbs[j].x, mBubbs[j].y, mBubbs[j].r * f, mPaint);
+ drawn++;
}
+ }
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ invalidateSelf();
return true;
}
- void setUnlockTries(int tries) {
- mDialDrawable.setUnlockTries(tries);
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ super.onBoundsChange(bounds);
+ randomize();
}
- private class BigDialDrawable extends Drawable {
- public final int STEPS = 10;
- private int mUnlockTries = 0;
- final Paint mPaint = new Paint();
- final Drawable mEleven;
- private boolean mNightMode;
- private float mValue = 0f;
- float mElevenAnim = 0f;
- ObjectAnimator mElevenShowAnimator = ObjectAnimator.ofFloat(this, "elevenAnim", 0f,
- 1f).setDuration(300);
- ObjectAnimator mElevenHideAnimator = ObjectAnimator.ofFloat(this, "elevenAnim", 1f,
- 0f).setDuration(500);
-
- BigDialDrawable() {
- mNightMode = getContext().getResources().getConfiguration().isNightModeActive();
- mEleven = getContext().getDrawable(R.drawable.ic_number11);
- mElevenShowAnimator.setInterpolator(new PathInterpolator(0.4f, 0f, 0.2f, 1f));
- mElevenHideAnimator.setInterpolator(new PathInterpolator(0.8f, 0.2f, 0.6f, 1f));
+ private void randomize() {
+ final float w = getBounds().width();
+ final float h = getBounds().height();
+ final float maxR = Math.min(w, h) / 3f;
+ mNumBubbs = 0;
+ if (avoid > 0f) {
+ mBubbs[mNumBubbs].x = w / 2f;
+ mBubbs[mNumBubbs].y = h / 2f;
+ mBubbs[mNumBubbs].r = avoid;
+ mBubbs[mNumBubbs].color = 0;
+ mNumBubbs++;
}
+ for (int j = 0; j < MAX_BUBBS; j++) {
+ // a simple but time-tested bubble-packing algorithm:
+ // 1. pick a spot
+ // 2. shrink the bubble until it is no longer overlapping any other bubble
+ // 3. if the bubble hasn't popped, keep it
+ int tries = 5;
+ while (tries-- > 0) {
+ float x = (float) Math.random() * w;
+ float y = (float) Math.random() * h;
+ float r = Math.min(Math.min(x, w - x), Math.min(y, h - y));
- public void setUnlockTries(int count) {
- if (mUnlockTries != count) {
- mUnlockTries = count;
- setValue(getValue());
- invalidateSelf();
- }
- }
-
- boolean isLocked() {
- return mUnlockTries > 0;
- }
-
- public void setValue(float v) {
- // until the dial is "unlocked", you can't turn it all the way to 11
- final float max = isLocked() ? 1f - 1f / STEPS : 1f;
- mValue = v < 0f ? 0f : v > max ? max : v;
- invalidateSelf();
- }
-
- public float getValue() {
- return mValue;
- }
-
- public int getUserLevel() {
- return Math.round(getValue() * STEPS - 0.25f);
- }
-
- public void setUserLevel(int i) {
- setValue(getValue() + ((float) i) / STEPS);
- }
-
- public float getElevenAnim() {
- return mElevenAnim;
- }
-
- public void setElevenAnim(float f) {
- if (mElevenAnim != f) {
- mElevenAnim = f;
- invalidateSelf();
- }
- }
-
- @Override
- public void draw(@NonNull Canvas canvas) {
- final Rect bounds = getBounds();
- final int w = bounds.width();
- final int h = bounds.height();
- final float w2 = w / 2f;
- final float h2 = h / 2f;
- final float radius = w / 4f;
-
- canvas.drawColor(mNightMode ? COLOR_NAVY : COLOR_LIGHTBLUE);
-
- canvas.save();
- canvas.rotate(45, w2, h2);
- canvas.clipRect(w2, h2 - radius, Math.min(w, h), h2 + radius);
- final int gradientColor = mNightMode ? 0x60000020 : (0x10FFFFFF & COLOR_NAVY);
- mPaint.setShader(
- new LinearGradient(w2, h2, Math.min(w, h), h2, gradientColor,
- 0x00FFFFFF & gradientColor, Shader.TileMode.CLAMP));
- mPaint.setColor(Color.BLACK);
- canvas.drawPaint(mPaint);
- mPaint.setShader(null);
- canvas.restore();
-
- mPaint.setStyle(Paint.Style.FILL);
- mPaint.setColor(COLOR_GREEN);
-
- canvas.drawCircle(w2, h2, radius, mPaint);
-
- mPaint.setColor(mNightMode ? COLOR_LIGHTBLUE : COLOR_NAVY);
- final float cx = w * 0.85f;
- for (int i = 0; i < STEPS; i++) {
- final float f = (float) i / STEPS;
- canvas.save();
- final float angle = valueToAngle(f);
- canvas.rotate(-angle, w2, h2);
- canvas.drawCircle(cx, h2, (i <= getUserLevel()) ? 20 : 5, mPaint);
- canvas.restore();
- }
-
- if (mElevenAnim > 0f) {
- final int color = COLOR_ORANGE;
- final int size2 = (int) ((0.5 + 0.5f * mElevenAnim) * w / 14);
- final float cx11 = cx + size2 / 4f;
- mEleven.setBounds((int) cx11 - size2, (int) h2 - size2,
- (int) cx11 + size2, (int) h2 + size2);
- final int alpha = 0xFFFFFF | ((int) clamp(0xFF * 2 * mElevenAnim, 0, 0xFF)
- << 24);
- mEleven.setTint(alpha & color);
- mEleven.draw(canvas);
- }
-
- // don't want to use the rounded value here since the quantization will be visible
- final float angle = valueToAngle(mValue);
-
- // it's easier to draw at far-right and rotate backwards
- canvas.rotate(-angle, w2, h2);
- mPaint.setColor(Color.WHITE);
- final float dimple = w2 / 12f;
- canvas.drawCircle(w - radius - dimple * 2, h2, dimple, mPaint);
- }
-
- float clamp(float x, float a, float b) {
- return x < a ? a : x > b ? b : x;
- }
-
- float angleToValue(float a) {
- return 1f - clamp(a / (360 - 45), 0f, 1f);
- }
-
- // rotation: min is at 4:30, max is at 3:00
- float valueToAngle(float v) {
- return (1f - v) * (360 - 45);
- }
-
- public void touchAngle(float a) {
- final int oldUserLevel = getUserLevel();
- final float newValue = angleToValue(a);
- // this is how we prevent the knob from snapping from max back to min, or from
- // jumping around wherever the user presses. The new value must be pretty close
- // to the
- // previous one.
- if (Math.abs(newValue - getValue()) < VALUE_CHANGE_MAX) {
- setValue(newValue);
-
- if (isLocked() && oldUserLevel != STEPS - 1 && getUserLevel() == STEPS - 1) {
- mUnlockTries--;
- } else if (!isLocked() && getUserLevel() == 0) {
- mUnlockTries = UNLOCK_TRIES;
+ // shrink radius to fit other bubbs
+ for (int i = 0; i < mNumBubbs; i++) {
+ r = (float) Math.min(r,
+ Math.hypot(x - mBubbs[i].x, y - mBubbs[i].y) - mBubbs[i].r
+ - padding);
+ if (r < minR) break;
}
- if (!isLocked()) {
- if (getUserLevel() == STEPS && mElevenAnim != 1f
- && !mElevenShowAnimator.isRunning()) {
- mElevenHideAnimator.cancel();
- mElevenShowAnimator.start();
- } else if (getUserLevel() != STEPS && mElevenAnim == 1f
- && !mElevenHideAnimator.isRunning()) {
- mElevenShowAnimator.cancel();
- mElevenHideAnimator.start();
- }
+ if (r >= minR) {
+ // we have found a spot for this bubble to live, let's save it and move on
+ r = Math.min(maxR, r);
+
+ mBubbs[mNumBubbs].x = x;
+ mBubbs[mNumBubbs].y = y;
+ mBubbs[mNumBubbs].r = r;
+ mBubbs[mNumBubbs].color = mColors[(int) (Math.random() * mColors.length)];
+ mNumBubbs++;
+ break;
}
}
}
+ Log.v(TAG, String.format("successfully placed %d bubbles (%d%%)",
+ mNumBubbs, (int) (100f * mNumBubbs / MAX_BUBBS)));
+ }
- @Override
- public void setAlpha(int i) {
- }
+ @Override
+ public void setAlpha(int alpha) { }
- @Override
- public void setColorFilter(@Nullable ColorFilter colorFilter) {
- }
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) { }
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
+ @Override
+ public int getOpacity() {
+ return TRANSLUCENT;
}
}
+
}
-
-
-
diff --git a/core/java/com/android/internal/inputmethod/EditableInputConnection.java b/core/java/com/android/internal/inputmethod/EditableInputConnection.java
index 6d4134a..410e68b 100644
--- a/core/java/com/android/internal/inputmethod/EditableInputConnection.java
+++ b/core/java/com/android/internal/inputmethod/EditableInputConnection.java
@@ -27,7 +27,6 @@
import android.text.Selection;
import android.text.method.KeyListener;
import android.util.Log;
-import android.util.imetracing.InputConnectionHelper;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
@@ -261,7 +260,7 @@
final long token = proto.start(fieldId);
CharSequence editableText = mTextView.getText();
CharSequence selectedText = getSelectedText(0 /* flags */);
- if (InputConnectionHelper.DUMP_TEXT) {
+ if (InputConnectionProtoDumper.DUMP_TEXT) {
if (editableText != null) {
proto.write(EDITABLE_TEXT, editableText.toString());
}
diff --git a/core/java/android/util/imetracing/ImeTracing.java b/core/java/com/android/internal/inputmethod/ImeTracing.java
similarity index 80%
rename from core/java/android/util/imetracing/ImeTracing.java
rename to core/java/com/android/internal/inputmethod/ImeTracing.java
index 4696ae3..8b21b7e 100644
--- a/core/java/android/util/imetracing/ImeTracing.java
+++ b/core/java/com/android/internal/inputmethod/ImeTracing.java
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-package android.util.imetracing;
+package com.android.internal.inputmethod;
import android.annotation.Nullable;
import android.app.ActivityThread;
import android.content.Context;
-import android.inputmethodservice.AbstractInputMethodService;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -36,8 +35,6 @@
* An abstract class that declares the methods for ime trace related operations - enable trace,
* schedule trace and add new trace to buffer. Both the client and server side classes can use
* it by getting an implementation through {@link ImeTracing#getInstance()}.
- *
- * @hide
*/
public abstract class ImeTracing {
@@ -94,6 +91,28 @@
}
/**
+ * Calling {@link IInputMethodManager#startImeTrace()}} to capture IME trace.
+ */
+ public final void startImeTrace() {
+ try {
+ mService.startImeTrace();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not start ime trace." + e);
+ }
+ }
+
+ /**
+ * Calling {@link IInputMethodManager#stopImeTrace()} to stop IME trace.
+ */
+ public final void stopImeTrace() {
+ try {
+ mService.stopImeTrace();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not stop ime trace." + e);
+ }
+ }
+
+ /**
* @param proto dump to be added to the buffer
*/
public abstract void addToBuffer(ProtoOutputStream proto, int source);
@@ -106,17 +125,33 @@
* @param icProto {@link android.view.inputmethod.InputConnection} call data in proto format.
*/
public abstract void triggerClientDump(String where, InputMethodManager immInstance,
- ProtoOutputStream icProto);
+ @Nullable byte[] icProto);
+
+ /**
+ * A delegate for {@link #triggerServiceDump(String, ServiceDumper, byte[])}.
+ */
+ @FunctionalInterface
+ public interface ServiceDumper {
+ /**
+ * Dumps internal data into {@link ProtoOutputStream}.
+ *
+ * @param proto {@link ProtoOutputStream} to be dumped into.
+ * @param icProto {@link android.view.inputmethod.InputConnection} call data in proto
+ * format.
+ */
+ void dumpToProto(ProtoOutputStream proto, @Nullable byte[] icProto);
+ }
/**
* Starts a proto dump of the currently connected InputMethodService information.
*
* @param where Place where the trace was triggered.
- * @param service The {@link android.inputmethodservice.InputMethodService} to be dumped.
+ * @param dumper {@link ServiceDumper} to be used to dump
+ * {@link android.inputmethodservice.InputMethodService}.
* @param icProto {@link android.view.inputmethod.InputConnection} call data in proto format.
*/
- public abstract void triggerServiceDump(String where, AbstractInputMethodService service,
- ProtoOutputStream icProto);
+ public abstract void triggerServiceDump(String where, ServiceDumper dumper,
+ @Nullable byte[] icProto);
/**
* Starts a proto dump of the InputMethodManagerService information.
diff --git a/core/java/android/util/imetracing/ImeTracingClientImpl.java b/core/java/com/android/internal/inputmethod/ImeTracingClientImpl.java
similarity index 88%
rename from core/java/android/util/imetracing/ImeTracingClientImpl.java
rename to core/java/com/android/internal/inputmethod/ImeTracingClientImpl.java
index 5a57a6a..31d278b 100644
--- a/core/java/android/util/imetracing/ImeTracingClientImpl.java
+++ b/core/java/com/android/internal/inputmethod/ImeTracingClientImpl.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package android.util.imetracing;
+package com.android.internal.inputmethod;
import android.annotation.NonNull;
-import android.inputmethodservice.AbstractInputMethodService;
+import android.annotation.Nullable;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
import android.util.Log;
@@ -27,7 +27,7 @@
import java.io.PrintWriter;
/**
- * @hide
+ * An implementation of {@link ImeTracing} for non system_server processes.
*/
class ImeTracingClientImpl extends ImeTracing {
ImeTracingClientImpl() throws ServiceNotFoundException, RemoteException {
@@ -40,7 +40,7 @@
@Override
public void triggerClientDump(String where, @NonNull InputMethodManager immInstance,
- ProtoOutputStream icProto) {
+ @Nullable byte[] icProto) {
if (!isEnabled() || !isAvailable()) {
return;
}
@@ -64,8 +64,8 @@
}
@Override
- public void triggerServiceDump(String where, @NonNull AbstractInputMethodService service,
- ProtoOutputStream icProto) {
+ public void triggerServiceDump(String where, @NonNull ServiceDumper dumper,
+ @Nullable byte[] icProto) {
if (!isEnabled() || !isAvailable()) {
return;
}
@@ -79,7 +79,7 @@
try {
ProtoOutputStream proto = new ProtoOutputStream();
- service.dumpProtoInternal(proto, icProto);
+ dumper.dumpToProto(proto, icProto);
sendToService(proto.getBytes(), IME_TRACING_FROM_IMS, where);
} catch (RemoteException e) {
Log.e(TAG, "Exception while sending ime-related service dump to server", e);
diff --git a/core/java/android/util/imetracing/ImeTracingServerImpl.java b/core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java
similarity index 96%
rename from core/java/android/util/imetracing/ImeTracingServerImpl.java
rename to core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java
index 06e4c50..d452e60 100644
--- a/core/java/android/util/imetracing/ImeTracingServerImpl.java
+++ b/core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-package android.util.imetracing;
+package com.android.internal.inputmethod;
import static android.os.Build.IS_USER;
import android.annotation.Nullable;
-import android.inputmethodservice.AbstractInputMethodService;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
import android.util.Log;
@@ -37,7 +36,7 @@
import java.io.PrintWriter;
/**
- * @hide
+ * An implementation of {@link ImeTracing} for the system_server process.
*/
class ImeTracingServerImpl extends ImeTracing {
private static final String TRACE_DIRNAME = "/data/misc/wmtrace/";
@@ -107,13 +106,12 @@
@Override
public void triggerClientDump(String where, InputMethodManager immInstance,
- ProtoOutputStream icProto) {
+ @Nullable byte[] icProto) {
// Intentionally left empty, this is implemented in ImeTracingClientImpl
}
@Override
- public void triggerServiceDump(String where, AbstractInputMethodService service,
- ProtoOutputStream icProto) {
+ public void triggerServiceDump(String where, ServiceDumper dumper, @Nullable byte[] icProto) {
// Intentionally left empty, this is implemented in ImeTracingClientImpl
}
diff --git a/core/java/android/util/imetracing/InputConnectionHelper.java b/core/java/com/android/internal/inputmethod/InputConnectionProtoDumper.java
similarity index 84%
rename from core/java/android/util/imetracing/InputConnectionHelper.java
rename to core/java/com/android/internal/inputmethod/InputConnectionProtoDumper.java
index 39f1e01..7172d0a 100644
--- a/core/java/android/util/imetracing/InputConnectionHelper.java
+++ b/core/java/com/android/internal/inputmethod/InputConnectionProtoDumper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.util.imetracing;
+package com.android.internal.inputmethod;
import static android.view.inputmethod.InputConnectionCallProto.GET_CURSOR_CAPS_MODE;
import static android.view.inputmethod.InputConnectionCallProto.GET_EXTRACTED_TEXT;
@@ -41,13 +41,12 @@
/**
* Helper class for constructing {@link android.view.inputmethod.InputConnection} dumps, which are
* integrated into {@link ImeTracing}.
- * @hide
*/
-public class InputConnectionHelper {
- static final String TAG = "InputConnectionHelper";
+public final class InputConnectionProtoDumper {
+ static final String TAG = "InputConnectionProtoDumper";
public static final boolean DUMP_TEXT = false;
- private InputConnectionHelper() {}
+ private InputConnectionProtoDumper() {}
/**
* Builder for InputConnectionCallProto to hold
@@ -59,10 +58,11 @@
* {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
* @param result The text after the cursor position; the length of the
* returned text might be less than <var>length</var>.
- * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ * @return Byte-array holding the InputConnectionCallProto data.
*/
- public static ProtoOutputStream buildGetTextAfterCursorProto(@IntRange(from = 0) int length,
- int flags, @Nullable CharSequence result) {
+ @NonNull
+ public static byte[] buildGetTextAfterCursorProto(@IntRange(from = 0) int length, int flags,
+ @Nullable CharSequence result) {
ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.start(GET_TEXT_AFTER_CURSOR);
proto.write(GetTextAfterCursor.LENGTH, length);
@@ -73,7 +73,7 @@
proto.write(GetTextAfterCursor.RESULT, result.toString());
}
proto.end(token);
- return proto;
+ return proto.getBytes();
}
/**
@@ -86,9 +86,10 @@
* {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
* @param result The text before the cursor position; the length of the
* returned text might be less than <var>length</var>.
- * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ * @return Byte-array holding the InputConnectionCallProto data.
*/
- public static ProtoOutputStream buildGetTextBeforeCursorProto(@IntRange(from = 0) int length,
+ @NonNull
+ public static byte[] buildGetTextBeforeCursorProto(@IntRange(from = 0) int length,
int flags, @Nullable CharSequence result) {
ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.start(GET_TEXT_BEFORE_CURSOR);
@@ -100,7 +101,7 @@
proto.write(GetTextBeforeCursor.RESULT, result.toString());
}
proto.end(token);
- return proto;
+ return proto.getBytes();
}
/**
@@ -114,10 +115,10 @@
* no text is selected. In {@link android.os.Build.VERSION_CODES#N} and
* later, returns false when the target application does not implement
* this method.
- * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ * @return Byte-array holding the InputConnectionCallProto data.
*/
- public static ProtoOutputStream buildGetSelectedTextProto(int flags,
- @Nullable CharSequence result) {
+ @NonNull
+ public static byte[] buildGetSelectedTextProto(int flags, @Nullable CharSequence result) {
ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.start(GET_SELECTED_TEXT);
proto.write(GetSelectedText.FLAGS, flags);
@@ -127,7 +128,7 @@
proto.write(GetSelectedText.RESULT, result.toString());
}
proto.end(token);
- return proto;
+ return proto.getBytes();
}
/**
@@ -139,16 +140,16 @@
* @param flags Supplies additional options controlling how the text is
* returned. May be either {@code 0} or
* {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
- * @param result an {@link android.view.inputmethod.SurroundingText} object describing the
+ * @param result an {@link SurroundingText} object describing the
* surrounding text and state of selection, or null if the input connection is no longer valid,
* or the editor can't comply with the request for some reason, or the application does not
* implement this method. The length of the returned text might be less than the sum of
* <var>beforeLength</var> and <var>afterLength</var> .
- * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ * @return Byte-array holding the InputConnectionCallProto data.
*/
- public static ProtoOutputStream buildGetSurroundingTextProto(@IntRange(from = 0)
- int beforeLength, @IntRange(from = 0) int afterLength, int flags,
- @Nullable SurroundingText result) {
+ @NonNull
+ public static byte[] buildGetSurroundingTextProto(@IntRange(from = 0) int beforeLength,
+ @IntRange(from = 0) int afterLength, int flags, @Nullable SurroundingText result) {
ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.start(GET_SURROUNDING_TEXT);
proto.write(GetSurroundingText.BEFORE_LENGTH, beforeLength);
@@ -169,7 +170,7 @@
proto.end(token_result);
}
proto.end(token);
- return proto;
+ return proto.getBytes();
}
/**
@@ -180,9 +181,10 @@
* {@link android.text.TextUtils#getCapsMode TextUtils.getCapsMode}.
* @param result the caps mode flags that are in effect at the current
* cursor position. See TYPE_TEXT_FLAG_CAPS_* in {@link android.text.InputType}.
- * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ * @return Byte-array holding the InputConnectionCallProto data.
*/
- public static ProtoOutputStream buildGetCursorCapsModeProto(int reqModes, int result) {
+ @NonNull
+ public static byte[] buildGetCursorCapsModeProto(int reqModes, int result) {
ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.start(GET_CURSOR_CAPS_MODE);
proto.write(GetCursorCapsMode.REQ_MODES, reqModes);
@@ -190,7 +192,7 @@
proto.write(GetCursorCapsMode.RESULT, result);
}
proto.end(token);
- return proto;
+ return proto.getBytes();
}
/**
@@ -199,17 +201,18 @@
* data.
*
* @param request Description of how the text should be returned.
- * {@link android.view.inputmethod.ExtractedTextRequest}
+ * {@link ExtractedTextRequest}
* @param flags Additional options to control the client, either {@code 0} or
* {@link android.view.inputmethod.InputConnection#GET_EXTRACTED_TEXT_MONITOR}.
- * @param result an {@link android.view.inputmethod.ExtractedText}
+ * @param result an {@link ExtractedText}
* object describing the state of the text view and containing the
* extracted text itself, or null if the input connection is no
* longer valid of the editor can't comply with the request for
* some reason.
- * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ * @return Byte-array holding the InputConnectionCallProto data.
*/
- public static ProtoOutputStream buildGetExtractedTextProto(@NonNull ExtractedTextRequest
+ @NonNull
+ public static byte[] buildGetExtractedTextProto(@NonNull ExtractedTextRequest
request, int flags, @Nullable ExtractedText result) {
ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.start(GET_EXTRACTED_TEXT);
@@ -226,6 +229,6 @@
proto.write(GetExtractedText.RESULT, result.text.toString());
}
proto.end(token);
- return proto;
+ return proto.getBytes();
}
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index e4e28a9..92d5a47 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -747,7 +747,7 @@
new DataOutputStream(sessionSocket.getOutputStream());
Credentials peerCredentials = sessionSocket.getPeerCredentials();
tmpArgBuffer = new ZygoteCommandBuffer(sessionSocket);
- args = ZygoteArguments.getInstance(argBuffer);
+ args = ZygoteArguments.getInstance(tmpArgBuffer);
applyUidSecurityPolicy(args, peerCredentials);
// TODO (chriswailes): Should this only be run for debug builds?
validateUsapCommand(args);
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 10f14b4..4f940db 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -25,6 +25,7 @@
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.service.notification.StatusBarNotification;
+import android.view.InsetsState;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.view.AppearanceRegion;
@@ -182,7 +183,7 @@
/**
* Notifies System UI side of system bar attribute change on the specified display.
*
- * @param displayId the ID of the display to notify
+ * @param displayId the ID of the display to notify.
* @param appearance the appearance of the focused window. The light top bar appearance is not
* controlled here, but primaryAppearance and secondaryAppearance.
* @param appearanceRegions a set of appearances which will be only applied in their own bounds.
@@ -191,11 +192,12 @@
* stacks.
* @param navbarColorManagedByIme {@code true} if navigation bar color is managed by IME.
* @param behavior the behavior of the focused window.
- * @param isFullscreen whether any of status or navigation bar is requested invisible.
+ * @param requestedState the collection of the requested visibilities of system insets.
+ * @param packageName the package name of the focused app.
*/
void onSystemBarAttributesChanged(int displayId, int appearance,
in AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- int behavior, boolean isFullscreen);
+ int behavior, in InsetsState requestedVisibilities, String packageName);
/**
* Notifies System UI to show transient bars. The transient bars are system bars, e.g., status
diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
index 8fb2f9c..2fd1691 100644
--- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
+++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
@@ -21,6 +21,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
+import android.view.InsetsState;
import com.android.internal.view.AppearanceRegion;
@@ -39,14 +40,15 @@
public final IBinder mImeToken;
public final boolean mNavbarColorManagedByIme;
public final int mBehavior;
- public final boolean mAppFullscreen;
+ public final InsetsState mRequestedState;
+ public final String mPackageName;
public final int[] mTransientBarTypes;
public RegisterStatusBarResult(ArrayMap<String, StatusBarIcon> icons, int disabledFlags1,
int appearance, AppearanceRegion[] appearanceRegions, int imeWindowVis,
int imeBackDisposition, boolean showImeSwitcher, int disabledFlags2, IBinder imeToken,
- boolean navbarColorManagedByIme, int behavior, boolean appFullscreen,
- @NonNull int[] transientBarTypes) {
+ boolean navbarColorManagedByIme, int behavior, InsetsState requestedState,
+ String packageName, @NonNull int[] transientBarTypes) {
mIcons = new ArrayMap<>(icons);
mDisabledFlags1 = disabledFlags1;
mAppearance = appearance;
@@ -58,7 +60,8 @@
mImeToken = imeToken;
mNavbarColorManagedByIme = navbarColorManagedByIme;
mBehavior = behavior;
- mAppFullscreen = appFullscreen;
+ mRequestedState = requestedState;
+ mPackageName = packageName;
mTransientBarTypes = transientBarTypes;
}
@@ -80,7 +83,8 @@
dest.writeStrongBinder(mImeToken);
dest.writeBoolean(mNavbarColorManagedByIme);
dest.writeInt(mBehavior);
- dest.writeBoolean(mAppFullscreen);
+ dest.writeTypedObject(mRequestedState, 0);
+ dest.writeString(mPackageName);
dest.writeIntArray(mTransientBarTypes);
}
@@ -104,12 +108,13 @@
final IBinder imeToken = source.readStrongBinder();
final boolean navbarColorManagedByIme = source.readBoolean();
final int behavior = source.readInt();
- final boolean appFullscreen = source.readBoolean();
+ final InsetsState requestedState = source.readTypedObject(InsetsState.CREATOR);
+ final String packageName = source.readString();
final int[] transientBarTypes = source.createIntArray();
return new RegisterStatusBarResult(icons, disabledFlags1, appearance,
appearanceRegions, imeWindowVis, imeBackDisposition, showImeSwitcher,
disabledFlags2, imeToken, navbarColorManagedByIme, behavior,
- appFullscreen, transientBarTypes);
+ requestedState, packageName, transientBarTypes);
}
@Override
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 783d088..6d1b4cb 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -27,8 +27,6 @@
import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;
-import android.util.imetracing.ImeTracing;
-import android.util.imetracing.InputConnectionHelper;
import android.util.proto.ProtoOutputStream;
import android.view.KeyEvent;
import android.view.View;
@@ -49,6 +47,8 @@
import com.android.internal.inputmethod.IExtractedTextResultCallback;
import com.android.internal.inputmethod.IIntResultCallback;
import com.android.internal.inputmethod.ISurroundingTextResultCallback;
+import com.android.internal.inputmethod.ImeTracing;
+import com.android.internal.inputmethod.InputConnectionProtoDumper;
import com.android.internal.os.SomeArgs;
import java.lang.ref.WeakReference;
@@ -350,7 +350,7 @@
}
void executeMessage(Message msg) {
- ProtoOutputStream icProto;
+ byte[] icProto;
switch (msg.what) {
case DO_GET_TEXT_AFTER_CURSOR: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextAfterCursor");
@@ -366,7 +366,7 @@
result = ic.getTextAfterCursor(msg.arg1, msg.arg2);
}
if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionHelper.buildGetTextAfterCursorProto(msg.arg1,
+ icProto = InputConnectionProtoDumper.buildGetTextAfterCursorProto(msg.arg1,
msg.arg2, result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getTextAfterCursor", mParentInputMethodManager, icProto);
@@ -396,7 +396,7 @@
result = ic.getTextBeforeCursor(msg.arg1, msg.arg2);
}
if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionHelper.buildGetTextBeforeCursorProto(msg.arg1,
+ icProto = InputConnectionProtoDumper.buildGetTextBeforeCursorProto(msg.arg1,
msg.arg2, result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getTextBeforeCursor", mParentInputMethodManager, icProto);
@@ -426,7 +426,8 @@
result = ic.getSelectedText(msg.arg1);
}
if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionHelper.buildGetSelectedTextProto(msg.arg1, result);
+ icProto = InputConnectionProtoDumper.buildGetSelectedTextProto(msg.arg1,
+ result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getSelectedText", mParentInputMethodManager, icProto);
}
@@ -459,8 +460,8 @@
result = ic.getSurroundingText(beforeLength, afterLength, flags);
}
if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionHelper.buildGetSurroundingTextProto(beforeLength,
- afterLength, flags, result);
+ icProto = InputConnectionProtoDumper.buildGetSurroundingTextProto(
+ beforeLength, afterLength, flags, result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getSurroundingText", mParentInputMethodManager, icProto);
}
@@ -489,7 +490,7 @@
result = ic.getCursorCapsMode(msg.arg1);
}
if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionHelper.buildGetCursorCapsModeProto(msg.arg1,
+ icProto = InputConnectionProtoDumper.buildGetCursorCapsModeProto(msg.arg1,
result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getCursorCapsMode", mParentInputMethodManager, icProto);
@@ -521,7 +522,7 @@
result = ic.getExtractedText(request, msg.arg1);
}
if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionHelper.buildGetExtractedTextProto(request,
+ icProto = InputConnectionProtoDumper.buildGetExtractedTextProto(request,
msg.arg1, result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getExtractedText", mParentInputMethodManager, icProto);
diff --git a/core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java b/core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java
new file mode 100644
index 0000000..481183e
--- /dev/null
+++ b/core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java
@@ -0,0 +1,179 @@
+/*
+ * 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.internal.widget;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This is a subclass of LinearLayout meant to be used in the Conversation header, to fix a bug
+ * when multiple user-provided strings are shown in the same conversation header. b/189723284
+ *
+ * This works around a deficiency in LinearLayout when shrinking views that it can't fully reduce
+ * all contents if any of the oversized views reaches zero.
+ */
+@RemoteViews.RemoteView
+public class ConversationHeaderLinearLayout extends LinearLayout {
+
+ public ConversationHeaderLinearLayout(Context context) {
+ super(context);
+ }
+
+ public ConversationHeaderLinearLayout(Context context,
+ @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public ConversationHeaderLinearLayout(Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ private int calculateTotalChildLength() {
+ final int count = getChildCount();
+ int totalLength = 0;
+
+ for (int i = 0; i < count; ++i) {
+ final View child = getChildAt(i);
+ if (child == null || child.getVisibility() == GONE) {
+ continue;
+ }
+ final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
+ child.getLayoutParams();
+ totalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
+ }
+ return totalLength + getPaddingLeft() + getPaddingRight();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ final int containerWidth = getMeasuredWidth();
+ final int contentsWidth = calculateTotalChildLength();
+
+ int excessContents = contentsWidth - containerWidth;
+ if (excessContents <= 0) {
+ return;
+ }
+ final int count = getChildCount();
+
+ float remainingWeight = 0;
+ List<ViewInfo> visibleChildrenToShorten = null;
+
+ // Find children which need to be shortened in order to ensure the contents fit.
+ for (int i = 0; i < count; ++i) {
+ final View child = getChildAt(i);
+ if (child == null || child.getVisibility() == View.GONE) {
+ continue;
+ }
+ final float weight = ((LayoutParams) child.getLayoutParams()).weight;
+ if (weight == 0) {
+ continue;
+ }
+ if (child.getMeasuredWidth() == 0) {
+ continue;
+ }
+ if (visibleChildrenToShorten == null) {
+ visibleChildrenToShorten = new LinkedList<>();
+ }
+ visibleChildrenToShorten.add(new ViewInfo(child));
+ remainingWeight += Math.max(0, weight);
+ }
+ if (visibleChildrenToShorten == null || visibleChildrenToShorten.isEmpty()) {
+ return;
+ }
+ balanceViewWidths(visibleChildrenToShorten, remainingWeight, excessContents);
+ remeasureChangedChildren(visibleChildrenToShorten);
+ }
+
+ /**
+ * Measure any child with a width that has changed.
+ */
+ private void remeasureChangedChildren(List<ViewInfo> childrenInfo) {
+ for (ViewInfo info : childrenInfo) {
+ if (info.mWidth != info.mStartWidth) {
+ final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+ Math.max(0, info.mWidth), MeasureSpec.EXACTLY);
+ final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+ info.mView.getMeasuredHeight(), MeasureSpec.EXACTLY);
+ info.mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ }
+ }
+ }
+
+ /**
+ * Given a list of view, use the weights to remove width from each view proportionally to the
+ * weight (and ignoring the view's actual width), but do this iteratively whenever a view is
+ * reduced to zero width, because in that case other views need reduction.
+ */
+ void balanceViewWidths(List<ViewInfo> viewInfos, float weightSum, int excessContents) {
+ boolean performAnotherPass = true;
+ // Loops only when all of the following are true:
+ // * `performAnotherPass` -- a view clamped to 0 width (or the first iteration)
+ // * `excessContents > 0` -- there is still horizontal space to allocate
+ // * `weightSum > 0` -- at least 1 view with nonzero width AND nonzero weight left
+ while (performAnotherPass && excessContents > 0 && weightSum > 0) {
+ int excessRemovedDuringThisPass = 0;
+ float weightSumForNextPass = 0;
+ performAnotherPass = false;
+ for (ViewInfo info : viewInfos) {
+ if (info.mWeight <= 0) {
+ continue;
+ }
+ if (info.mWidth <= 0) {
+ continue;
+ }
+ int newWidth = (int) (info.mWidth - (excessContents * (info.mWeight / weightSum)));
+ if (newWidth < 0) {
+ newWidth = 0;
+ performAnotherPass = true;
+ }
+ excessRemovedDuringThisPass += info.mWidth - newWidth;
+ info.mWidth = newWidth;
+ if (info.mWidth > 0) {
+ weightSumForNextPass += info.mWeight;
+ }
+ }
+ excessContents -= excessRemovedDuringThisPass;
+ weightSum = weightSumForNextPass;
+ }
+ }
+
+ /**
+ * A helper class for measuring children.
+ */
+ static class ViewInfo {
+ final View mView;
+ final float mWeight;
+ final int mStartWidth;
+ int mWidth;
+
+ ViewInfo(View view) {
+ this.mView = view;
+ this.mWeight = ((LayoutParams) view.getLayoutParams()).weight;
+ this.mStartWidth = this.mWidth = view.getMeasuredWidth();
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java
index 1974b0c..07ee9b5 100644
--- a/core/java/com/android/internal/widget/NotificationExpandButton.java
+++ b/core/java/com/android/internal/widget/NotificationExpandButton.java
@@ -20,7 +20,6 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.RemotableViewMethod;
@@ -159,8 +158,7 @@
if (mHighlightPillColor != 0) {
mPillView.setBackgroundTintList(ColorStateList.valueOf(mHighlightPillColor));
}
- mPillView.setBackgroundTintMode(PorterDuff.Mode.SRC_IN);
- mIconView.setColorFilter(mHighlightTextColor, PorterDuff.Mode.SRC_IN);
+ mIconView.setColorFilter(mHighlightTextColor);
if (mHighlightTextColor != 0) {
mNumberView.setTextColor(mHighlightTextColor);
}
@@ -168,8 +166,7 @@
if (mDefaultPillColor != 0) {
mPillView.setBackgroundTintList(ColorStateList.valueOf(mDefaultPillColor));
}
- mPillView.setBackgroundTintMode(PorterDuff.Mode.SRC_IN);
- mIconView.setColorFilter(mDefaultTextColor, PorterDuff.Mode.SRC_IN);
+ mIconView.setColorFilter(mDefaultTextColor);
if (mDefaultTextColor != 0) {
mNumberView.setTextColor(mDefaultTextColor);
}
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 6e2b9cf..0ec296b 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -207,6 +207,7 @@
jmethodID getId;
jmethodID getResonantFrequency;
jmethodID getQFactor;
+ jmethodID getMaxAmplitude;
} gVibratorMethods;
static Mutex gLock;
@@ -2677,6 +2678,8 @@
vibratorInfo.resonantFrequency =
env->CallFloatMethod(jVibrator.get(), gVibratorMethods.getResonantFrequency);
vibratorInfo.qFactor = env->CallFloatMethod(jVibrator.get(), gVibratorMethods.getQFactor);
+ vibratorInfo.maxAmplitude =
+ env->CallFloatMethod(jVibrator.get(), gVibratorMethods.getMaxAmplitude);
vibratorInfos.push_back(vibratorInfo);
}
return (jint)check_AudioSystem_Command(AudioSystem::setVibratorInfos(vibratorInfos));
@@ -3041,6 +3044,8 @@
gVibratorMethods.getResonantFrequency =
GetMethodIDOrDie(env, vibratorClass, "getResonantFrequency", "()F");
gVibratorMethods.getQFactor = GetMethodIDOrDie(env, vibratorClass, "getQFactor", "()F");
+ gVibratorMethods.getMaxAmplitude =
+ GetMethodIDOrDie(env, vibratorClass, "getHapticChannelMaximumAmplitude", "()F");
AudioSystem::addErrorCallback(android_media_AudioSystem_error_callback);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7047690..c6317cc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5904,8 +5904,8 @@
android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.PlatLogoActivity"
- android:theme="@style/Theme.DeviceDefault.DayNight"
- android:configChanges="orientation|keyboardHidden"
+ android:theme="@style/Theme.DeviceDefault.Wallpaper.NoTitleBar"
+ android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:icon="@drawable/platlogo"
android:process=":ui">
</activity>
diff --git a/core/res/res/drawable-hdpi/clock_dial.png b/core/res/res/drawable-hdpi/clock_dial.png
deleted file mode 100644
index 9de29bc..0000000
--- a/core/res/res/drawable-hdpi/clock_dial.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/clock_hand_hour.png b/core/res/res/drawable-hdpi/clock_hand_hour.png
deleted file mode 100644
index 9f7e5c0..0000000
--- a/core/res/res/drawable-hdpi/clock_hand_hour.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/clock_hand_minute.png b/core/res/res/drawable-hdpi/clock_hand_minute.png
deleted file mode 100644
index 2eec380..0000000
--- a/core/res/res/drawable-hdpi/clock_hand_minute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/clock_dial.png b/core/res/res/drawable-ldpi/clock_dial.png
deleted file mode 100644
index cbc9961..0000000
--- a/core/res/res/drawable-ldpi/clock_dial.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/clock_hand_hour.png b/core/res/res/drawable-ldpi/clock_hand_hour.png
deleted file mode 100644
index 3362fd0..0000000
--- a/core/res/res/drawable-ldpi/clock_hand_hour.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/clock_hand_minute.png b/core/res/res/drawable-ldpi/clock_hand_minute.png
deleted file mode 100644
index 5c73d45..0000000
--- a/core/res/res/drawable-ldpi/clock_hand_minute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/clock_dial.png b/core/res/res/drawable-mdpi/clock_dial.png
deleted file mode 100644
index 82f73fe..0000000
--- a/core/res/res/drawable-mdpi/clock_dial.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/clock_hand_hour.png b/core/res/res/drawable-mdpi/clock_hand_hour.png
deleted file mode 100644
index 1f0aec8..0000000
--- a/core/res/res/drawable-mdpi/clock_hand_hour.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/clock_hand_minute.png b/core/res/res/drawable-mdpi/clock_hand_minute.png
deleted file mode 100644
index 6cd8a4b..0000000
--- a/core/res/res/drawable-mdpi/clock_hand_minute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/clock_dial.xml b/core/res/res/drawable-nodpi/clock_dial.xml
new file mode 100644
index 0000000..5263218
--- /dev/null
+++ b/core/res/res/drawable-nodpi/clock_dial.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="380dp"
+ android:height="380dp"
+ android:viewportWidth="380"
+ android:viewportHeight="380">
+ <path
+ android:pathData="M177.389,2.803C185.381,-0.934 194.619,-0.934 202.611,2.803L231.193,16.169C234.358,17.649 237.76,18.56 241.242,18.861L272.677,21.577C281.467,22.336 289.468,26.956 294.52,34.188L312.59,60.054C314.591,62.919 317.081,65.409 319.946,67.41L345.812,85.48C353.044,90.533 357.664,98.533 358.423,107.323L361.139,138.758C361.44,142.24 362.351,145.642 363.832,148.807L377.197,177.389C380.934,185.381 380.934,194.619 377.197,202.611L363.832,231.193C362.351,234.359 361.44,237.76 361.139,241.242L358.423,272.677C357.664,281.467 353.044,289.468 345.812,294.52L319.946,312.59C317.081,314.591 314.591,317.081 312.59,319.946L294.52,345.812C289.468,353.044 281.467,357.664 272.677,358.423L241.242,361.139C237.76,361.44 234.359,362.351 231.193,363.832L202.611,377.197C194.619,380.934 185.381,380.934 177.389,377.197L148.807,363.832C145.642,362.351 142.24,361.44 138.758,361.139L107.323,358.423C98.533,357.664 90.533,353.044 85.48,345.812L67.41,319.946C65.409,317.081 62.919,314.591 60.054,312.59L34.188,294.52C26.956,289.468 22.336,281.467 21.577,272.677L18.861,241.242C18.56,237.76 17.649,234.359 16.169,231.193L2.803,202.611C-0.934,194.619 -0.934,185.381 2.803,177.389L16.169,148.807C17.649,145.642 18.56,142.24 18.861,138.758L21.577,107.323C22.336,98.533 26.956,90.533 34.188,85.48L60.054,67.41C62.919,65.409 65.409,62.919 67.41,60.054L85.48,34.188C90.533,26.956 98.533,22.336 107.323,21.577L138.758,18.861C142.24,18.56 145.642,17.649 148.807,16.169L177.389,2.803Z"
+ android:fillColor="@color/system_neutral1_200"/>
+</vector>
diff --git a/core/res/res/drawable-nodpi/clock_hand_hour.xml b/core/res/res/drawable-nodpi/clock_hand_hour.xml
new file mode 100644
index 0000000..de165a4
--- /dev/null
+++ b/core/res/res/drawable-nodpi/clock_hand_hour.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="380dp"
+ android:height="380dp"
+ android:viewportWidth="380"
+ android:viewportHeight="380">
+ <path
+ android:pathData="M190,96L190,96A16,16 0,0 1,206 112L206,190A16,16 0,0 1,190 206L190,206A16,16 0,0 1,174 190L174,112A16,16 0,0 1,190 96z"
+ android:fillColor="@color/system_accent1_700"/>
+</vector>
diff --git a/core/res/res/drawable-nodpi/clock_hand_minute.xml b/core/res/res/drawable-nodpi/clock_hand_minute.xml
new file mode 100644
index 0000000..72cac6e
--- /dev/null
+++ b/core/res/res/drawable-nodpi/clock_hand_minute.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="380dp"
+ android:height="380dp"
+ android:viewportWidth="380"
+ android:viewportHeight="380">
+ <path
+ android:pathData="M190,60L190,60A16,16 0,0 1,206 76L206,190A16,16 0,0 1,190 206L190,206A16,16 0,0 1,174 190L174,76A16,16 0,0 1,190 60z"
+ android:fillColor="@color/system_accent2_500"/>
+</vector>
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
index b01eb39..1d67570 100644
--- a/core/res/res/drawable-nodpi/platlogo.xml
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -1,50 +1,36 @@
+<!--
+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.
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="512dp"
- android:height="512dp"
- android:viewportWidth="512"
- android:viewportHeight="512">
- <path
- android:fillColor="#F86734"
- android:pathData="M416.23 236.62h-10.67c-1.46 0-2.65-1.19-2.65-2.65v-9.85c0-1.47 1.19-2.65 2.65-2.65h23.37c1.47 0 2.66 1.19 2.66 2.65v66.9c0 1.46-1.2 2.65-2.66 2.65H418.9c-1.47 0-2.66-1.19-2.66-2.65v-54.4z"/>
- <path
- android:fillColor="#F86734"
- android:pathData="M455.51 236.62h-10.67c-1.47 0-2.65-1.19-2.65-2.65v-9.85c0-1.47 1.18-2.65 2.65-2.65h23.37c1.47 0 2.66 1.19 2.66 2.65v66.9c0 1.46-1.2 2.65-2.66 2.65h-10.05c-1.46 0-2.65-1.19-2.65-2.65v-54.4z"/>
- <path
- android:fillColor="#D6F0FF"
- android:pathData="M364.12 400.25a4.34 4.34 0 1 0 0 8.68a4.34 4.34 0 1 0 0-8.68z"/>
- <path
- android:fillColor="#D6F0FF"
- android:pathData="M275.46 433.53a4.84 4.84 0 1 0 0 9.68a4.84 4.84 0 1 0 0-9.68z"/>
- <path
- android:fillColor="#D6F0FF"
- android:pathData="M184.52 418.83a5.36 5.36 0 1 0 0 10.72a5.36 5.36 0 1 0 0-10.72z"/>
- <path
- android:fillColor="#D6F0FF"
- android:pathData="M110.42 359.19a5.89 5.89 0 1 0 0 11.78a5.89 5.89 0 1 0 0-11.78z"/>
- <path
- android:fillColor="#D6F0FF"
- android:pathData="M75.94 270.17a6.43 6.43 0 1 0 0 12.86a6.43 6.43 0 1 0 0-12.86z"/>
- <path
- android:fillColor="#D6F0FF"
- android:pathData="M89.48 178.57a6.98 6.98 0 1 0 0 13.96a6.98 6.98 0 1 0 0-13.96z"/>
- <path
- android:fillColor="#D6F0FF"
- android:pathData="M147.97 103.54a7.54 7.54 0 1 0 0 15.08a7.54 7.54 0 1 0 0-15.08z"/>
- <path
- android:fillColor="#D6F0FF"
- android:pathData="M236.63 66.7a8.1 8.1 0 1 0 0 16.2a8.1 8.1 0 1 0 0-16.2z"/>
- <path
- android:fillColor="#D6F0FF"
- android:pathData="M327.09 78.3a8.66 8.66 0 1 0 0 17.32a8.66 8.66 0 1 0 0-17.32z"/>
- <path
- android:fillColor="#D6F0FF"
- android:pathData="M401.05 136.97a9.22 9.22 0 1 0 0 18.44a9.22 9.22 0 1 0 0-18.44z"/>
- <group>
- <path
- android:fillColor="#3DDB85"
- android:pathData="M255.45 129.46a128.11 128.11 0 1 0 0 256.22a128.11 128.11 0 1 0 0-256.22z"/>
- <path
- android:fillColor="#FFF"
- android:pathData="M339.23 236.09a21.48 21.48 0 1 0 0 42.96a21.48 21.48 0 1 0 0-42.96z"/>
- </group>
+ android:width="128dp"
+ android:height="128dp"
+ android:viewportWidth="128"
+ android:viewportHeight="128">
+ <path
+ android:pathData="M64,64m-64,0a64,64 0,1 1,128 0a64,64 0,1 1,-128 0"
+ android:fillColor="@android:color/system_accent3_500"/>
+ <path
+ android:pathData="M32.5,34.15a10,10 0,0 1,9.94 10V93.85"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#fff"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M95.5,93.85H55.71V83.9A19.9,19.9 0,0 1,75.61 64h10a9.94,9.94 0,0 0,9.94 -10,19.9 19.9,0 0,0 -38.69,-6.56A20.77,20.77 0,0 0,56 50.73"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#fff"
+ android:strokeLineCap="round"/>
</vector>
diff --git a/core/res/res/drawable-xhdpi/clock_dial.png b/core/res/res/drawable-xhdpi/clock_dial.png
deleted file mode 100644
index 6cb60a2..0000000
--- a/core/res/res/drawable-xhdpi/clock_dial.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/clock_hand_hour.png b/core/res/res/drawable-xhdpi/clock_hand_hour.png
deleted file mode 100644
index bc0c5bd..0000000
--- a/core/res/res/drawable-xhdpi/clock_hand_hour.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/clock_hand_minute.png b/core/res/res/drawable-xhdpi/clock_hand_minute.png
deleted file mode 100644
index 01d611f..0000000
--- a/core/res/res/drawable-xhdpi/clock_hand_minute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/ic_lock.xml b/core/res/res/drawable/ic_lock.xml
index 7582d5f..c30f963 100644
--- a/core/res/res/drawable/ic_lock.xml
+++ b/core/res/res/drawable/ic_lock.xml
@@ -14,14 +14,23 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32dp"
- android:height="32dp"
- android:viewportWidth="32.0"
- android:viewportHeight="32.0">
+ android:width="26dp"
+ android:height="36dp"
+ android:viewportWidth="26"
+ android:viewportHeight="36">
<path
android:fillColor="#FF000000"
- android:pathData="M16,20m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
+ android:pathData="M13.75 27.5 C15.13,27.5 16.25,26.38 16.25,25 C16.25,23.62 15.13,22.5 13.75,22.5 C12.37,22.5 11.25,23.62 11.25,25 C11.25,26.38 12.37,27.5 13.75,27.5c " />
<path
- android:fillColor="#FF000000"
- android:pathData="M24,11h-2.3V7.3c0,-3.1 -2.5,-5.7 -5.7,-5.7c-3.1,0 -5.7,2.5 -5.7,5.7V11H8c-1.3,0 -2.3,1 -2.3,2.3v13.3c0,1.3 1,2.3 2.3,2.3h16c1.3,0 2.3,-1 2.3,-2.3V13.3C26.3,12 25.3,11 24,11zM12.3,7.3c0,-2 1.6,-3.7 3.7,-3.7c2,0 3.7,1.6 3.7,3.7V11h-7.3V7.3zM24.3,26.7c0,0.2 -0.1,0.3 -0.3,0.3H8c-0.2,0 -0.3,-0.1 -0.3,-0.3V13.3C7.7,13.1 7.8,13 8,13h16c0.2,0 0.3,0.1 0.3,0.3V26.7z"/>
+ android:strokeColor="#FF000000"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2.5"
+ android:pathData="M4.5 15 C4.5,15 23,15 23,15 C24.1,15 25,15.9 25,17 C25,17 25,33 25,33 C25,34.1 24.1,35 23,35 C23,35 4.5,35 4.5,35 C3.4,35 2.5,34.1 2.5,33 C2.5,33 2.5,17 2.5,17 C2.5,15.9 3.4,15 4.5,15c " />
+ <path
+ android:strokeColor="#FF000000"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2.5"
+ android:pathData="M7.5 15 C7.5,15 7.5,8.61 7.5,8.61 C7.5,5.24 10.3,2.5 13.75,2.5 C17.2,2.5 20,5.24 20,8.61 C20,8.61 20,15 20,15 " />
</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_lock_open.xml b/core/res/res/drawable/ic_lock_open.xml
index e0deb598..abe6dde 100644
--- a/core/res/res/drawable/ic_lock_open.xml
+++ b/core/res/res/drawable/ic_lock_open.xml
@@ -14,14 +14,23 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32dp"
- android:height="32dp"
- android:viewportWidth="32.0"
- android:viewportHeight="32.0">
+ android:height="36dp"
+ android:width="34dp"
+ android:viewportHeight="36"
+ android:viewportWidth="34">
<path
android:fillColor="#FF000000"
- android:pathData="M16,20m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
+ android:pathData="M13.75 27.5 C15.13,27.5 16.25,26.38 16.25,25 C16.25,23.62 15.13,22.5 13.75,22.5 C12.37,22.5 11.25,23.62 11.25,25 C11.25,26.38 12.37,27.5 13.75,27.5c " />
<path
- android:fillColor="#FF000000"
- android:pathData="M25.3,1.7c-3.1,0 -5.7,2.5 -5.7,5.7V11H8c-1.3,0 -2.3,1 -2.3,2.3v13.3c0,1.3 1,2.3 2.3,2.3h16c1.3,0 2.3,-1 2.3,-2.3V13.3c0,-1.3 -1,-2.3 -2.3,-2.3h-2.3V7.3c0,-2 1.6,-3.7 3.7,-3.7c2,0 3.7,1.6 3.7,3.7V8h2V7.3C31,4.2 28.5,1.7 25.3,1.7zM24.3,13.3v13.3c0,0.2 -0.1,0.3 -0.3,0.3H8c-0.2,0 -0.3,-0.1 -0.3,-0.3V13.3C7.7,13.1 7.8,13 8,13h16C24.2,13 24.3,13.1 24.3,13.3z"/>
+ android:strokeColor="#FF000000"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2.5"
+ android:pathData=" M4.5 15 C4.5,15 23,15 23,15 C24.1,15 25,15.9 25,17 C25,17 25,33 25,33 C25,34.1 24.1,35 23,35 C23,35 4.5,35 4.5,35 C3.4,35 2.5,34.1 2.5,33 C2.5,33 2.5,17 2.5,17 C2.5,15.9 3.4,15 4.5,15c " />
+ <path
+ android:strokeColor="#FF000000"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2.5"
+ android:pathData="M20 15 C20,15 20,8.61 20,8.61 C20,5.24 22.8,2.5 26.25,2.5 C29.7,2.5 32.5,5.24 32.5,8.61 C32.5,8.61 32.5,15 32.5,15 " />
</vector>
\ No newline at end of file
diff --git a/core/res/res/layout/notification_template_conversation_header.xml b/core/res/res/layout/notification_template_conversation_header.xml
index 389637eb..2faff41 100644
--- a/core/res/res/layout/notification_template_conversation_header.xml
+++ b/core/res/res/layout/notification_template_conversation_header.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<LinearLayout
+<com.android.internal.widget.ConversationHeaderLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/conversation_header"
android:layout_width="wrap_content"
@@ -119,6 +119,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
+ android:layout_weight="100"
android:showRelative="true"
android:singleLine="true"
android:visibility="gone"
@@ -171,4 +172,4 @@
android:src="@drawable/ic_notifications_alerted"
android:visibility="gone"
/>
-</LinearLayout>
+</com.android.internal.widget.ConversationHeaderLinearLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9802f8d..ffc2f3b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4820,7 +4820,7 @@
<!-- Blur radius for the Option 3 in R.integer.config_letterboxBackgroundType. Values < 0 are
ignored and 0 is used. -->
- <dimen name="config_letterboxBackgroundWallpaperBlurRadius">100dp</dimen>
+ <dimen name="config_letterboxBackgroundWallpaperBlurRadius">31dp</dimen>
<!-- Alpha of a black translucent scrim showed over wallpaper letterbox background when
the Option 3 is selected for R.integer.config_letterboxBackgroundType.
diff --git a/core/tests/coretests/src/android/graphics/FontListParserTest.java b/core/tests/coretests/src/android/graphics/FontListParserTest.java
index 22f6ec0..701e619 100644
--- a/core/tests/coretests/src/android/graphics/FontListParserTest.java
+++ b/core/tests/coretests/src/android/graphics/FontListParserTest.java
@@ -27,6 +27,7 @@
import static junit.framework.Assert.fail;
+import android.graphics.fonts.FontCustomizationParser;
import android.graphics.fonts.FontStyle;
import android.os.LocaleList;
import android.text.FontConfig;
@@ -46,6 +47,7 @@
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
+import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -318,6 +320,52 @@
}
}
+ @Test
+ public void alias() throws Exception {
+ String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<familyset>"
+ + " <family name='sans-serif'>"
+ + " <font>test.ttf</font>"
+ + " </family>"
+ + " <family name='custom-family'>"
+ + " <font>missing.ttf</font>"
+ + " </family>"
+ + " <alias name='custom-alias' to='sans-serif'/>"
+ + "</familyset>";
+ FontConfig config = readFamilies(xml, true /* include non-existing font files */);
+ List<FontConfig.Alias> aliases = config.getAliases();
+ assertThat(aliases.size()).isEqualTo(1);
+ assertThat(aliases.get(0).getName()).isEqualTo("custom-alias");
+ assertThat(aliases.get(0).getOriginal()).isEqualTo("sans-serif");
+ }
+
+ @Test
+ public void dropped_FamilyAlias() throws Exception {
+ String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<familyset>"
+ + " <family name='sans-serif'>"
+ + " <font>test.ttf</font>"
+ + " </family>"
+ + " <family name='custom-family'>"
+ + " <font>missing.ttf</font>"
+ + " </family>"
+ + " <alias name='custom-alias' to='custom-family'/>"
+ + "</familyset>";
+ FontConfig config = readFamilies(xml, false /* exclude not existing file */);
+ assertThat(config.getAliases()).isEmpty();
+ }
+
+ private FontConfig readFamilies(String xml, boolean allowNonExisting)
+ throws IOException, XmlPullParserException {
+ ByteArrayInputStream buffer = new ByteArrayInputStream(
+ xml.getBytes(StandardCharsets.UTF_8));
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(buffer, "UTF-8");
+ parser.nextTag();
+ return FontListParser.readFamilies(parser, "", new FontCustomizationParser.Result(), null,
+ 0L /* last modified date */, 0 /* config version */, allowNonExisting);
+ }
+
private FontConfig.FontFamily readFamily(String xml)
throws IOException, XmlPullParserException {
ByteArrayInputStream buffer = new ByteArrayInputStream(
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index e53fc07..fd7753b 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -832,4 +832,80 @@
return compositeName.equals(result.getString(Settings.NameValueTable.VALUE));
}
+ @Test
+ public void deleteProperty_nullNamespace() {
+ try {
+ DeviceConfig.deleteProperty(null, KEY);
+ Assert.fail("Null namespace should have resulted in an NPE.");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void deleteProperty_nullName() {
+ try {
+ DeviceConfig.deleteProperty(NAMESPACE, null);
+ Assert.fail("Null name should have resulted in an NPE.");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void deletePropertyString() {
+ final String value = "new_value";
+ final String default_value = "default";
+ DeviceConfig.setProperty(NAMESPACE, KEY, value, false);
+ DeviceConfig.deleteProperty(NAMESPACE, KEY);
+ final String result = DeviceConfig.getString(NAMESPACE, KEY, default_value);
+ assertThat(result).isEqualTo(default_value);
+ }
+
+ @Test
+ public void deletePropertyBoolean() {
+ final boolean value = true;
+ final boolean default_value = false;
+ DeviceConfig.setProperty(NAMESPACE, KEY, String.valueOf(value), false);
+ DeviceConfig.deleteProperty(NAMESPACE, KEY);
+ final boolean result = DeviceConfig.getBoolean(NAMESPACE, KEY, default_value);
+ assertThat(result).isEqualTo(default_value);
+ }
+
+ @Test
+ public void deletePropertyInt() {
+ final int value = 123;
+ final int default_value = 999;
+ DeviceConfig.setProperty(NAMESPACE, KEY, String.valueOf(value), false);
+ DeviceConfig.deleteProperty(NAMESPACE, KEY);
+ final int result = DeviceConfig.getInt(NAMESPACE, KEY, default_value);
+ assertThat(result).isEqualTo(default_value);
+ }
+
+ @Test
+ public void deletePropertyLong() {
+ final long value = 456789;
+ final long default_value = 123456;
+ DeviceConfig.setProperty(NAMESPACE, KEY, String.valueOf(value), false);
+ DeviceConfig.deleteProperty(NAMESPACE, KEY);
+ final long result = DeviceConfig.getLong(NAMESPACE, KEY, default_value);
+ assertThat(result).isEqualTo(default_value);
+ }
+
+ @Test
+ public void deletePropertyFloat() {
+ final float value = 456.789f;
+ final float default_value = 123.456f;
+ DeviceConfig.setProperty(NAMESPACE, KEY, String.valueOf(value), false);
+ DeviceConfig.deleteProperty(NAMESPACE, KEY);
+ final float result = DeviceConfig.getFloat(NAMESPACE, KEY, default_value);
+ assertThat(result).isEqualTo(default_value);
+ }
+
+ @Test
+ public void deleteProperty_empty() {
+ assertThat(DeviceConfig.deleteProperty(NAMESPACE, KEY)).isTrue();
+ final String result = DeviceConfig.getString(NAMESPACE, KEY, null);
+ assertThat(result).isNull();
+ }
}
diff --git a/core/tests/coretests/src/android/window/WindowContextControllerTest.java b/core/tests/coretests/src/android/window/WindowContextControllerTest.java
index 020f4a0..a6e351d 100644
--- a/core/tests/coretests/src/android/window/WindowContextControllerTest.java
+++ b/core/tests/coretests/src/android/window/WindowContextControllerTest.java
@@ -22,12 +22,15 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import android.content.res.Configuration;
import android.os.Binder;
import android.platform.test.annotations.Presubmit;
import android.view.IWindowManager;
@@ -38,6 +41,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
/**
* Tests for {@link WindowContextController}
@@ -53,15 +58,18 @@
@Presubmit
public class WindowContextControllerTest {
private WindowContextController mController;
+ @Mock
private IWindowManager mMockWms;
+ @Mock
+ private WindowTokenClient mMockToken;
@Before
public void setUp() throws Exception {
- mMockWms = mock(IWindowManager.class);
- mController = new WindowContextController(new Binder(), mMockWms);
-
- doReturn(true).when(mMockWms).attachWindowContextToDisplayArea(any(), anyInt(),
- anyInt(), any());
+ MockitoAnnotations.initMocks(this);
+ mController = new WindowContextController(mMockToken, mMockWms);
+ doNothing().when(mMockToken).onConfigurationChanged(any(), anyInt(), anyBoolean());
+ doReturn(new Configuration()).when(mMockWms).attachWindowContextToDisplayArea(any(),
+ anyInt(), anyInt(), any());
}
@Test(expected = IllegalStateException.class)
@@ -85,6 +93,8 @@
null /* options */);
assertThat(mController.mAttachedToDisplayArea).isTrue();
+ verify(mMockToken).onConfigurationChanged(any(), eq(DEFAULT_DISPLAY),
+ eq(false) /* shouldReportConfigChange */);
mController.detachIfNeeded();
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 4ef45e2..b59b84bb 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -580,11 +580,11 @@
final long[] cpuTimesMs4 = getAllCpuFreqTimes(sTestPkgUid, PROCESS_STATE_TOP);
assertCpuTimesValid(cpuTimesMs4);
actualCpuTimeMs = 0;
- for (int i = 0; i < cpuTimesMs.length / 2; ++i) {
- actualCpuTimeMs += cpuTimesMs[i];
+ for (int i = 0; i < cpuTimesMs4.length / 2; ++i) {
+ actualCpuTimeMs += cpuTimesMs4[i];
}
assertApproximateValue("Incorrect total cpu time, " + msgCpuTimes,
- WORK_DURATION_MS, actualCpuTimeMs);
+ 2 * WORK_DURATION_MS, actualCpuTimeMs);
batteryOffScreenOn();
} finally {
diff --git a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
index 272f228..7d4412c 100644
--- a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
+++ b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
@@ -24,6 +24,7 @@
import android.os.Parcel;
import android.os.UserHandle;
import android.util.ArrayMap;
+import android.view.InsetsState;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -59,7 +60,8 @@
new Binder() /* imeToken */,
true /* navbarColorManagedByIme */,
BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE,
- true /* appFullscreen */,
+ new InsetsState() /* requestedState */,
+ "test" /* packageName */,
new int[0] /* transientBarTypes */);
final RegisterStatusBarResult copy = clone(original);
@@ -79,7 +81,8 @@
assertThat(copy.mImeToken).isSameInstanceAs(original.mImeToken);
assertThat(copy.mNavbarColorManagedByIme).isEqualTo(original.mNavbarColorManagedByIme);
assertThat(copy.mBehavior).isEqualTo(original.mBehavior);
- assertThat(copy.mAppFullscreen).isEqualTo(original.mAppFullscreen);
+ assertThat(copy.mRequestedState).isEqualTo(original.mRequestedState);
+ assertThat(copy.mPackageName).isEqualTo(original.mPackageName);
assertThat(copy.mTransientBarTypes).isEqualTo(original.mTransientBarTypes);
}
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index 084e1db..d1e4322 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -130,6 +130,13 @@
}
prebuilt_etc {
+ name: "allowed_privapp_com.google.android.car.adaslocation",
+ sub_dir: "permissions",
+ src: "com.google.android.car.adaslocation.xml",
+ filename_from_src: true,
+}
+
+prebuilt_etc {
name: "allowed_privapp_com.google.android.car.kitchensink",
sub_dir: "permissions",
src: "com.google.android.car.kitchensink.xml",
diff --git a/data/etc/car/com.google.android.car.adaslocation.xml b/data/etc/car/com.google.android.car.adaslocation.xml
new file mode 100644
index 0000000..cc1ef3c
--- /dev/null
+++ b/data/etc/car/com.google.android.car.adaslocation.xml
@@ -0,0 +1,21 @@
+<?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.
+ -->
+<permissions>
+ <privapp-permissions package="com.google.android.car.adaslocation">
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 677656c5..3e37237 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -79,12 +79,6 @@
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/Transition.java"
},
- "-2029985709": {
- "message": "setFocusedTask: taskId=%d",
- "level": "DEBUG",
- "group": "WM_DEBUG_FOCUS",
- "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
- },
"-2024464438": {
"message": "app-onAnimationFinished(): mOuter=%s",
"level": "DEBUG",
@@ -187,6 +181,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-1924376693": {
+ "message": " Setting Ready-group to %b. group=%s from %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"-1918702467": {
"message": "onSyncFinishedDrawing %s",
"level": "VERBOSE",
@@ -613,6 +613,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1442613680": {
+ "message": " Creating Ready-group for Transition %d with root=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"-1438175584": {
"message": "Input focus has changed to %s display=%d",
"level": "VERBOSE",
@@ -1783,6 +1789,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/TaskFragment.java"
},
+ "-55185509": {
+ "message": "setFocusedTask: taskId=%d touchedActivity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_FOCUS",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-50336993": {
"message": "moveFocusableActivityToTop: activity=%s",
"level": "DEBUG",
@@ -2209,6 +2221,12 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "352982444": {
+ "message": " allReady query: used=%b override=%b states=[%s]",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"355720268": {
"message": "stopFreezingDisplayLocked: Unfreezing now",
"level": "DEBUG",
@@ -3277,6 +3295,12 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/InsetsStateController.java"
},
+ "1670933628": {
+ "message": " Setting allReady override",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"1671994402": {
"message": "Nulling last startingData",
"level": "VERBOSE",
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 93a336e..96b3325 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -25,6 +25,7 @@
import android.os.Build;
import android.os.LocaleList;
import android.text.FontConfig;
+import android.util.ArraySet;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
@@ -37,6 +38,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.regex.Pattern;
/**
@@ -120,7 +122,23 @@
}
}
- private static FontConfig readFamilies(
+ /**
+ * Parses the familyset tag in font.xml
+ * @param parser a XML pull parser
+ * @param fontDir A system font directory, e.g. "/system/fonts"
+ * @param customization A OEM font customization
+ * @param updatableFontMap A map of updated font files
+ * @param lastModifiedDate A date that the system font is updated.
+ * @param configVersion A version of system font config.
+ * @param allowNonExistingFile true if allowing non-existing font files during parsing fonts.xml
+ * @return result of fonts.xml
+ *
+ * @throws XmlPullParserException
+ * @throws IOException
+ *
+ * @hide
+ */
+ public static FontConfig readFamilies(
@NonNull XmlPullParser parser,
@NonNull String fontDir,
@NonNull FontCustomizationParser.Result customization,
@@ -159,7 +177,24 @@
}
families.addAll(oemNamedFamilies.values());
- return new FontConfig(families, aliases, lastModifiedDate, configVersion);
+
+ // Filters aliases that point to non-existing families.
+ Set<String> namedFamilies = new ArraySet<>();
+ for (int i = 0; i < families.size(); ++i) {
+ String name = families.get(i).getName();
+ if (name != null) {
+ namedFamilies.add(name);
+ }
+ }
+ List<FontConfig.Alias> filtered = new ArrayList<>();
+ for (int i = 0; i < aliases.size(); ++i) {
+ FontConfig.Alias alias = aliases.get(i);
+ if (namedFamilies.contains(alias.getOriginal())) {
+ filtered.add(alias);
+ }
+ }
+
+ return new FontConfig(families, filtered, lastModifiedDate, configVersion);
}
private static boolean keepReading(XmlPullParser parser)
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index fe04f0d..187ddd8 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -1106,6 +1106,43 @@
ProcessInitializer.sInstance.setContext(context);
}
+ /**
+ * Returns true if HardwareRender will produce output.
+ *
+ * This value is global to the process and affects all uses of HardwareRenderer,
+ * including
+ * those created by the system such as those used by the View tree when using hardware
+ * accelerated rendering.
+ *
+ * Default is true in all production environments, but may be false in testing-focused
+ * emulators or if {@link #setDrawingEnabled(boolean)} is used.
+ */
+ public static boolean isDrawingEnabled() {
+ return nIsDrawingEnabled();
+ }
+
+ /**
+ * Toggles whether or not HardwareRenderer will produce drawing output globally in the current
+ * process.
+ *
+ * This applies to all HardwareRenderer instances, including those created by the platform such
+ * as those used by the system for hardware accelerated View rendering.
+ *
+ * The capability to disable drawing output is intended for test environments, primarily
+ * headless ones. By setting this to false, tests that launch activities or interact with Views
+ * can be quicker with less RAM usage by skipping the final step of View drawing. All View
+ * lifecycle events will occur as normal, only the final step of rendering on the GPU to the
+ * display will be skipped.
+ *
+ * This can be toggled on and off at will, so screenshot tests can also run in this same
+ * environment by toggling drawing back on and forcing a frame to be drawn such as by calling
+ * view#invalidate(). Once drawn and the screenshot captured, this can then be turned back off.
+ */
+ // TODO: Add link to androidx's Screenshot library for help with this
+ public static void setDrawingEnabled(boolean drawingEnabled) {
+ nSetDrawingEnabled(drawingEnabled);
+ }
+
private static final class DestroyContextRunnable implements Runnable {
private final long mNativeInstance;
@@ -1438,4 +1475,8 @@
private static native void nInitDisplayInfo(int width, int height, float refreshRate,
int wideColorDataspace, long appVsyncOffsetNanos, long presentationDeadlineNanos);
+
+ private static native void nSetDrawingEnabled(boolean drawingEnabled);
+
+ private static native boolean nIsDrawingEnabled();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
index 0b941b5..9113c79 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
@@ -103,6 +103,8 @@
return runMoveToSideStage(args, pw);
case "removeFromSideStage":
return runRemoveFromSideStage(args, pw);
+ case "setSideStageOutline":
+ return runSetSideStageOutline(args, pw);
case "setSideStagePosition":
return runSetSideStagePosition(args, pw);
case "setSideStageVisibility":
@@ -161,6 +163,18 @@
return true;
}
+ private boolean runSetSideStageOutline(String[] args, PrintWriter pw) {
+ if (args.length < 3) {
+ // First arguments are "WMShell" and command name.
+ pw.println("Error: whether to enable or disable side stage outline border should be"
+ + " provided as arguments");
+ return false;
+ }
+ final boolean enable = new Boolean(args[2]);
+ mSplitScreenOptional.ifPresent(split -> split.setSideStageOutline(enable));
+ return true;
+ }
+
private boolean runSetSideStagePosition(String[] args, PrintWriter pw) {
if (args.length < 3) {
// First arguments are "WMShell" and command name.
@@ -175,7 +189,7 @@
private boolean runSetSideStageVisibility(String[] args, PrintWriter pw) {
if (args.length < 3) {
// First arguments are "WMShell" and command name.
- pw.println("Error: side stage position should be provided as arguments");
+ pw.println("Error: side stage visibility should be provided as arguments");
return false;
}
final Boolean visible = new Boolean(args[2]);
@@ -197,6 +211,8 @@
pw.println(" Move a task with given id in split-screen mode.");
pw.println(" removeFromSideStage <taskId>");
pw.println(" Remove a task with given id in split-screen mode.");
+ pw.println(" setSideStageOutline <true/false>");
+ pw.println(" Enable/Disable outline on the side-stage.");
pw.println(" setSideStagePosition <SideStagePosition>");
pw.println(" Sets the position of the side-stage.");
pw.println(" setSideStageVisibility <true/false>");
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 efff3e3..6c3576b 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
@@ -614,6 +614,12 @@
}
private void onEndOfSwipePipToHomeTransition() {
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ mInSwipePipToHomeTransition = false;
+ mSwipePipToHomeOverlay = null;
+ return;
+ }
+
final Rect destinationBounds = mPipBoundsState.getBounds();
final SurfaceControl swipeToHomeOverlay = mSwipePipToHomeOverlay;
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index b75cde0..18153e3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -32,6 +32,7 @@
import android.app.TaskInfo;
import android.content.Context;
+import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.Surface;
@@ -214,6 +215,25 @@
final Rect currentBounds = taskInfo.configuration.windowConfiguration.getBounds();
PipAnimationController.PipTransitionAnimator animator;
finishTransaction.setPosition(leash, destinationBounds.left, destinationBounds.top);
+ if (taskInfo.pictureInPictureParams != null
+ && taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
+ mOneShotAnimationType = ANIM_TYPE_BOUNDS;
+
+ // PiP menu is attached late in the process here to avoid any artifacts on the leash
+ // caused by addShellRoot when in gesture navigation mode.
+ mPipMenuController.attach(leash);
+ SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+ tx.setMatrix(leash, Matrix.IDENTITY_MATRIX, new float[9])
+ .setPosition(leash, destinationBounds.left, destinationBounds.top)
+ .setWindowCrop(leash, destinationBounds.width(), destinationBounds.height());
+ startTransaction.merge(tx);
+ startTransaction.apply();
+ mPipBoundsState.setBounds(destinationBounds);
+ onFinishResize(taskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, tx);
+ sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
+ mFinishCallback = null;
+ return true;
+ }
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
final Rect sourceHintRect =
PipBoundsAlgorithm.getValidSourceHintRect(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java
index 5d5a6e5..0b763f2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java
@@ -38,8 +38,6 @@
import com.android.wm.shell.R;
-import java.util.function.Supplier;
-
/**
* Handles drawing outline of the bounds of provided root surface. The outline will be drown with
* the consideration of display insets like status bar, navigation bar and display cutout.
@@ -47,67 +45,71 @@
class OutlineManager extends WindowlessWindowManager {
private static final String WINDOW_NAME = "SplitOutlineLayer";
private final Context mContext;
- private final int mOutlineColor;
private final Rect mOutlineBounds = new Rect();
private final Rect mTmpBounds = new Rect();
- private final Supplier<SurfaceControl> mOutlineSurfaceSupplier;
private SurfaceControlViewHost mViewHost;
+ private SurfaceControl mHostLeash;
+ private SurfaceControl mLeash;
+ private int mOutlineColor;
- /**
- * Constructs {@link #OutlineManager} with indicated outline color for the provided root
- * surface.
- */
- OutlineManager(Context context, Configuration configuration,
- Supplier<SurfaceControl> outlineSurfaceSupplier, int color) {
+ OutlineManager(Context context, Configuration configuration) {
super(configuration, null /* rootSurface */, null /* hostInputToken */);
- mContext = context.createDisplayContext(context.getDisplay());
- mOutlineSurfaceSupplier = outlineSurfaceSupplier;
- mOutlineColor = color;
+ mContext = context.createWindowContext(context.getDisplay(), TYPE_APPLICATION_OVERLAY,
+ null /* options */);
}
@Override
protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
- b.setParent(mOutlineSurfaceSupplier.get());
+ b.setParent(mHostLeash);
}
- boolean updateOutlineBounds(Rect rootBounds) {
+ boolean drawOutlineBounds(Rect rootBounds) {
+ if (mLeash == null || mViewHost == null) return false;
+
computeOutlineBounds(mContext, rootBounds, mTmpBounds);
if (mOutlineBounds.equals(mTmpBounds)) {
return false;
}
mOutlineBounds.set(mTmpBounds);
- if (mViewHost == null) {
- mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
- }
- if (mViewHost.getView() == null) {
- final OutlineRoot rootView = (OutlineRoot) LayoutInflater.from(mContext)
- .inflate(R.layout.split_outline, null);
- rootView.updateOutlineBounds(mOutlineBounds, mOutlineColor);
-
- final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- rootBounds.width(), rootBounds.height(),
- TYPE_APPLICATION_OVERLAY,
- FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE,
- PixelFormat.TRANSLUCENT);
- lp.token = new Binder();
- lp.setTitle(WINDOW_NAME);
- lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
- // TODO(b/189839391): Set INPUT_FEATURE_NO_INPUT_CHANNEL after WM supports
- // TRUSTED_OVERLAY for windowless window without input channel.
- mViewHost.setView(rootView, lp);
- } else {
- ((OutlineRoot) mViewHost.getView()).updateOutlineBounds(mOutlineBounds, mOutlineColor);
- final WindowManager.LayoutParams lp =
- (WindowManager.LayoutParams) mViewHost.getView().getLayoutParams();
- lp.width = rootBounds.width();
- lp.height = rootBounds.height();
- mViewHost.relayout(lp);
- }
+ ((OutlineRoot) mViewHost.getView()).updateOutlineBounds(mOutlineBounds, mOutlineColor);
+ final WindowManager.LayoutParams lp =
+ (WindowManager.LayoutParams) mViewHost.getView().getLayoutParams();
+ lp.width = rootBounds.width();
+ lp.height = rootBounds.height();
+ mViewHost.relayout(lp);
return true;
}
+ void inflate(SurfaceControl.Transaction t, SurfaceControl hostLeash, int color) {
+ if (mLeash != null || mViewHost != null) return;
+
+ mHostLeash = hostLeash;
+ mOutlineColor = color;
+ mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+ final OutlineRoot rootView = (OutlineRoot) LayoutInflater.from(mContext)
+ .inflate(R.layout.split_outline, null);
+
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ 0 /* width */, 0 /* height */, TYPE_APPLICATION_OVERLAY,
+ FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT);
+ lp.token = new Binder();
+ lp.setTitle(WINDOW_NAME);
+ lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
+ // TODO(b/189839391): Set INPUT_FEATURE_NO_INPUT_CHANNEL after WM supports
+ // TRUSTED_OVERLAY for windowless window without input channel.
+ mViewHost.setView(rootView, lp);
+ mLeash = getSurfaceControl(mViewHost.getWindowToken());
+ t.setLayer(mLeash, Integer.MAX_VALUE);
+ }
+
+ void release() {
+ if (mViewHost != null) {
+ mViewHost.release();
+ }
+ }
+
private static void computeOutlineBounds(Context context, Rect rootBounds, Rect outBounds) {
computeDisplayStableBounds(context, outBounds);
outBounds.intersect(rootBounds);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index a0bdcc3..2b19bb9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
-import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -52,7 +51,7 @@
final WindowContainerToken rootToken = mRootTaskInfo.token;
wct.setBounds(rootToken, rootBounds)
.reparent(task.token, rootToken, true /* onTop*/)
- // Moving the root task to top after the child tasks were repareted , or the root
+ // Moving the root task to top after the child tasks were reparented , or the root
// task cannot be visible and focused.
.reorder(rootToken, true /* onTop */);
}
@@ -78,25 +77,33 @@
return true;
}
- @Override
- @CallSuper
- public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- super.onTaskAppeared(taskInfo, leash);
- if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId) {
- mOutlineManager = new OutlineManager(mContext, mRootTaskInfo.configuration,
- () -> mRootLeash,
- Color.YELLOW);
+ void enableOutline(boolean enable) {
+ if (enable) {
+ if (mOutlineManager == null && mRootTaskInfo != null) {
+ mOutlineManager = new OutlineManager(mContext, mRootTaskInfo.configuration);
+ mSyncQueue.runInSync(t -> mOutlineManager.inflate(t, mRootLeash, Color.YELLOW));
+ updateOutlineBounds();
+ }
+ } else {
+ if (mOutlineManager != null) {
+ mOutlineManager.release();
+ mOutlineManager = null;
+ }
}
}
+ private void updateOutlineBounds() {
+ if (mOutlineManager == null || mRootTaskInfo == null || !mRootTaskInfo.isVisible) return;
+ mOutlineManager.drawOutlineBounds(
+ mRootTaskInfo.configuration.windowConfiguration.getBounds());
+ }
+
@Override
@CallSuper
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
super.onTaskInfoChanged(taskInfo);
- if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId
- && mRootTaskInfo.isRunning) {
- mOutlineManager.updateOutlineBounds(
- mRootTaskInfo.configuration.windowConfiguration.getBounds());
+ if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId) {
+ updateOutlineBounds();
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 36b2777..d60fa29 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -142,6 +142,10 @@
return mStageCoordinator.removeFromSideStage(taskId);
}
+ public void setSideStageOutline(boolean enable) {
+ mStageCoordinator.setSideStageOutline(enable);
+ }
+
public void setSideStagePosition(@SplitPosition int sideStagePosition) {
mStageCoordinator.setSideStagePosition(sideStagePosition);
}
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 4e91193..67b5ab3 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
@@ -232,6 +232,10 @@
return result;
}
+ void setSideStageOutline(boolean enable) {
+ mSideStage.enableOutline(enable);
+ }
+
/** Starts 2 tasks in one transition. */
void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
@Nullable Bundle sideOptions, @SplitPosition int sidePosition,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 0fd8eca62..4f73fee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -71,8 +71,8 @@
}
private final StageListenerCallbacks mCallbacks;
- private final SyncTransactionQueue mSyncQueue;
private final SurfaceSession mSurfaceSession;
+ protected final SyncTransactionQueue mSyncQueue;
protected ActivityManager.RunningTaskInfo mRootTaskInfo;
protected SurfaceControl mRootLeash;
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 75dd561..107a3f8 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
@@ -127,11 +127,13 @@
* parallel.
*
* @param suggestType Suggest type to create the splash screen view.
- * @param consumer Receiving the SplashScreenView object, which will also be executed
- * on splash screen thread. Note that the view can be null if failed.
+ * @param splashScreenViewConsumer Receiving the SplashScreenView object, which will also be
+ * executed on splash screen thread. Note that the view can be
+ * null if failed.
+ * @param bgColorConsumer Receiving the background color once it's estimated complete.
*/
void createContentView(Context context, @StartingWindowType int suggestType, ActivityInfo info,
- int taskId, Consumer<SplashScreenView> consumer) {
+ int taskId, Consumer<SplashScreenView> splashScreenViewConsumer) {
mSplashscreenWorkerHandler.post(() -> {
SplashScreenView contentView;
try {
@@ -143,7 +145,7 @@
+ taskId, e);
contentView = null;
}
- consumer.accept(contentView);
+ splashScreenViewConsumer.accept(contentView);
});
}
@@ -160,7 +162,10 @@
com.android.wm.shell.R.dimen.starting_surface_exit_animation_window_shift_length);
}
- private static int getSystemBGColor() {
+ /**
+ * @return Current system background color.
+ */
+ public static int getSystemBGColor() {
final Context systemContext = ActivityThread.currentApplication();
if (systemContext == null) {
Slog.e(TAG, "System context does not exist!");
@@ -170,12 +175,22 @@
return res.getColor(com.android.wm.shell.R.color.splash_window_background_default);
}
+ /**
+ * Estimate the background color of the app splash screen, this may take a while so use it only
+ * if there is no starting window exists for that context.
+ **/
+ int estimateTaskBackgroundColor(Context context) {
+ final SplashScreenWindowAttrs windowAttrs = new SplashScreenWindowAttrs();
+ getWindowAttrs(context, windowAttrs);
+ return peekWindowBGColor(context, windowAttrs);
+ }
+
private static Drawable createDefaultBackgroundDrawable() {
return new ColorDrawable(getSystemBGColor());
}
/** Extract the window background color from {@code attrs}. */
- public static int peekWindowBGColor(Context context, SplashScreenWindowAttrs attrs) {
+ private static int peekWindowBGColor(Context context, SplashScreenWindowAttrs attrs) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "peekWindowBGColor");
final Drawable themeBGDrawable;
if (attrs.mWindowBgColor != 0) {
@@ -255,7 +270,7 @@
* Get the {@link SplashScreenWindowAttrs} from {@code context} and fill them into
* {@code attrs}.
*/
- public static void getWindowAttrs(Context context, SplashScreenWindowAttrs attrs) {
+ private static void getWindowAttrs(Context context, SplashScreenWindowAttrs attrs) {
final TypedArray typedArray = context.obtainStyledAttributes(
com.android.internal.R.styleable.Window);
attrs.mWindowBgResId = typedArray.getResourceId(R.styleable.Window_windowBackground, 0);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
index 079d689..01c9b66 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.startingsurface;
+import android.app.TaskInfo;
+import android.graphics.Color;
/**
* Interface to engage starting window feature.
*/
@@ -27,4 +29,11 @@
default IStartingWindow createExternalInterface() {
return null;
}
+
+ /**
+ * Returns the background color for a starting window if existing.
+ */
+ default int getBackgroundColor(TaskInfo taskInfo) {
+ return Color.BLACK;
+ }
}
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 4dc5447..243751fe 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
@@ -26,17 +26,22 @@
import android.annotation.Nullable;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
+import android.app.ActivityThread;
+import android.app.TaskInfo;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.IBinder;
import android.os.RemoteCallback;
+import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
import android.util.Slog;
@@ -149,6 +154,12 @@
return context.createDisplayContext(targetDisplay);
}
+ private int getSplashScreenTheme(int splashScreenThemeResId, ActivityInfo activityInfo) {
+ return splashScreenThemeResId != 0
+ ? splashScreenThemeResId
+ : activityInfo.getThemeResource() != 0 ? activityInfo.getThemeResource()
+ : com.android.internal.R.style.Theme_DeviceDefault_DayNight;
+ }
/**
* Called when a task need a splash screen starting window.
*
@@ -170,10 +181,7 @@
final int taskId = taskInfo.taskId;
Context context = mContext;
// replace with the default theme if the application didn't set
- final int theme = windowInfo.splashScreenThemeResId != 0
- ? windowInfo.splashScreenThemeResId
- : activityInfo.getThemeResource() != 0 ? activityInfo.getThemeResource()
- : com.android.internal.R.style.Theme_DeviceDefault_DayNight;
+ final int theme = getSplashScreenTheme(windowInfo.splashScreenThemeResId, activityInfo);
if (DEBUG_SPLASH_SCREEN) {
Slog.d(TAG, "addSplashScreen " + activityInfo.packageName
+ " theme=" + Integer.toHexString(theme) + " task=" + taskInfo.taskId
@@ -336,6 +344,10 @@
// the window before first round relayoutWindow, which will happen after insets
// animation.
mChoreographer.postCallback(CALLBACK_INSETS_ANIMATION, setViewSynchronized, null);
+ // Block until we get the background color.
+ final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
+ final SplashScreenView contentView = viewSupplier.get();
+ record.mBGColor = contentView.getInitBackgroundColor();
}
} catch (RuntimeException e) {
// don't crash if something else bad happens, for example a
@@ -346,11 +358,11 @@
}
int getStartingWindowBackgroundColorForTask(int taskId) {
- StartingWindowRecord startingWindowRecord = mStartingWindowRecords.get(taskId);
- if (startingWindowRecord == null || startingWindowRecord.mContentView == null) {
- return 0;
+ final StartingWindowRecord startingWindowRecord = mStartingWindowRecords.get(taskId);
+ if (startingWindowRecord == null) {
+ return Color.TRANSPARENT;
}
- return startingWindowRecord.mContentView.getInitBackgroundColor();
+ return startingWindowRecord.mBGColor;
}
private static class SplashScreenViewSupplier implements Supplier<SplashScreenView> {
@@ -378,6 +390,43 @@
}
}
+ int estimateTaskBackgroundColor(TaskInfo taskInfo) {
+ if (taskInfo.topActivityInfo == null) {
+ return Color.TRANSPARENT;
+ }
+ final ActivityInfo activityInfo = taskInfo.topActivityInfo;
+ final String packageName = activityInfo.packageName;
+ final int userId = taskInfo.userId;
+ final Context windowContext;
+ try {
+ windowContext = mContext.createPackageContextAsUser(
+ packageName, Context.CONTEXT_RESTRICTED, UserHandle.of(userId));
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Failed creating package context with package name "
+ + packageName + " for user " + taskInfo.userId, e);
+ return Color.TRANSPARENT;
+ }
+ try {
+ final IPackageManager packageManager = ActivityThread.getPackageManager();
+ final String splashScreenThemeName = packageManager.getSplashScreenTheme(packageName,
+ userId);
+ final int splashScreenThemeId = splashScreenThemeName != null
+ ? windowContext.getResources().getIdentifier(splashScreenThemeName, null, null)
+ : 0;
+
+ final int theme = getSplashScreenTheme(splashScreenThemeId, activityInfo);
+
+ if (theme != windowContext.getThemeResId()) {
+ windowContext.setTheme(theme);
+ }
+ return mSplashscreenContentDrawer.estimateTaskBackgroundColor(windowContext);
+ } catch (RuntimeException | RemoteException e) {
+ Slog.w(TAG, "failed get starting window background color at taskId: "
+ + taskInfo.taskId, e);
+ }
+ return Color.TRANSPARENT;
+ }
+
/**
* Called when a task need a snapshot starting window.
*/
@@ -556,19 +605,16 @@
private SplashScreenView mContentView;
private boolean mSetSplashScreen;
private @StartingWindowType int mSuggestType;
-
- StartingWindowRecord(IBinder appToken, View decorView,
- TaskSnapshotWindow taskSnapshotWindow) {
- mAppToken = appToken;
- mDecorView = decorView;
- mTaskSnapshotWindow = taskSnapshotWindow;
- }
+ private int mBGColor;
StartingWindowRecord(IBinder appToken, View decorView,
TaskSnapshotWindow taskSnapshotWindow, @StartingWindowType int suggestType) {
mAppToken = appToken;
mDecorView = decorView;
mTaskSnapshotWindow = taskSnapshotWindow;
+ if (mTaskSnapshotWindow != null) {
+ mBGColor = mTaskSnapshotWindow.getBackgroundColor();
+ }
mSuggestType = suggestType;
}
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 eaa89d8..e84d498 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
@@ -18,18 +18,23 @@
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_LEGACY_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 com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.TaskInfo;
import android.content.Context;
+import android.graphics.Color;
import android.graphics.Rect;
+import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Slog;
+import android.util.SparseIntArray;
import android.view.SurfaceControl;
import android.window.StartingWindowInfo;
import android.window.StartingWindowInfo.StartingWindowType;
@@ -38,6 +43,7 @@
import androidx.annotation.BinderThread;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.function.TriConsumer;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
@@ -62,10 +68,11 @@
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.
- public static final boolean DEBUG_SPLASH_SCREEN = true;
+ public static final boolean DEBUG_SPLASH_SCREEN = Build.isDebuggable();
public static final boolean DEBUG_TASK_SNAPSHOT = false;
+ private static final long TASK_BG_COLOR_RETAIN_TIME_MS = 5000;
+
private final StartingSurfaceDrawer mStartingSurfaceDrawer;
private final StartingWindowTypeAlgorithm mStartingWindowTypeAlgorithm;
@@ -73,6 +80,11 @@
private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
private final Context mContext;
private final ShellExecutor mSplashScreenExecutor;
+ /**
+ * Need guarded because it has exposed to StartingSurface
+ */
+ @GuardedBy("mTaskBackgroundColors")
+ private final SparseIntArray mTaskBackgroundColors = new SparseIntArray();
public StartingWindowController(Context context, ShellExecutor splashScreenExecutor,
StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, TransactionPool pool) {
@@ -125,13 +137,19 @@
final TaskSnapshot snapshot = windowInfo.mTaskSnapshot;
mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken,
snapshot);
- } else /* suggestionType == STARTING_WINDOW_TYPE_NONE */ {
- // Don't add a staring window.
}
- if (mTaskLaunchingCallback != null && isSplashScreenType(suggestionType)) {
+ if (suggestionType != STARTING_WINDOW_TYPE_NONE) {
int taskId = runningTaskInfo.taskId;
- int color = mStartingSurfaceDrawer.getStartingWindowBackgroundColorForTask(taskId);
- mTaskLaunchingCallback.accept(taskId, suggestionType, color);
+ int color = mStartingSurfaceDrawer
+ .getStartingWindowBackgroundColorForTask(taskId);
+ if (color != Color.TRANSPARENT) {
+ synchronized (mTaskBackgroundColors) {
+ mTaskBackgroundColors.append(taskId, color);
+ }
+ }
+ if (mTaskLaunchingCallback != null && isSplashScreenType(suggestionType)) {
+ mTaskLaunchingCallback.accept(taskId, suggestionType, color);
+ }
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -163,9 +181,13 @@
*/
public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
boolean playRevealAnimation) {
- mSplashScreenExecutor.execute(() -> {
- mStartingSurfaceDrawer.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
- });
+ mSplashScreenExecutor.execute(() -> mStartingSurfaceDrawer.removeStartingWindow(
+ taskId, leash, frame, playRevealAnimation));
+ mSplashScreenExecutor.executeDelayed(() -> {
+ synchronized (mTaskBackgroundColors) {
+ mTaskBackgroundColors.delete(taskId);
+ }
+ }, TASK_BG_COLOR_RETAIN_TIME_MS);
}
/**
@@ -182,6 +204,19 @@
mIStartingWindow = new IStartingWindowImpl(StartingWindowController.this);
return mIStartingWindow;
}
+
+ @Override
+ public int getBackgroundColor(TaskInfo taskInfo) {
+ synchronized (mTaskBackgroundColors) {
+ final int index = mTaskBackgroundColors.indexOfKey(taskInfo.taskId);
+ if (index >= 0) {
+ return mTaskBackgroundColors.valueAt(index);
+ }
+ }
+ final int color = mStartingSurfaceDrawer.estimateTaskBackgroundColor(taskInfo);
+ return color != Color.TRANSPARENT
+ ? color : SplashscreenContentDrawer.getSystemBGColor();
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 382d580..6052d3d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -283,6 +283,10 @@
mClearWindowHandler = clearWindowHandler;
}
+ int getBackgroundColor() {
+ return mBackgroundPaint.getColor();
+ }
+
/**
* Ask system bar background painter to draw status bar background.
* @hide
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
index cc861f9..b95193a1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
@@ -22,7 +22,10 @@
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.Assume.assumeFalse
+import org.junit.Before
import org.junit.Test
abstract class RotateTwoLaunchedAppsTransition(
@@ -52,6 +55,13 @@
}
}
+ @Before
+ override fun setup() {
+ // AppPairs hasn't been updated to Shell Transition. There will be conflict on rotation.
+ assumeFalse(isShellTransitionsEnabled())
+ super.setup()
+ }
+
@FlakyTest
@Test
override fun navBarLayerIsVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
index 4fe69ad..f15044e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
@@ -20,6 +20,7 @@
import android.content.ComponentName
import android.content.pm.PackageManager.FEATURE_LEANBACK
import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY
+import android.os.SystemProperties
import android.support.test.launcherhelper.LauncherStrategyFactory
import android.util.Log
import androidx.test.uiautomator.By
@@ -60,6 +61,9 @@
companion object {
private const val APP_CLOSE_WAIT_TIME_MS = 3_000L
+ fun isShellTransitionsEnabled() =
+ SystemProperties.getBoolean("persist.debug.shell_transit", false)
+
fun executeShellCommand(instrumentation: Instrumentation, cmd: String) {
try {
SystemUtil.runShellCommand(instrumentation, cmd)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
index d8cc660..666d259 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
@@ -33,10 +33,12 @@
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.getDevEnableNonResizableMultiWindow
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setDevEnableNonResizableMultiWindow
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.After
+import org.junit.Assume.assumeFalse
import org.junit.Before
import org.junit.Test
@@ -54,6 +56,8 @@
@Before
open fun setup() {
+ // Legacy split is having some issue with Shell transition, and will be deprecated soon.
+ assumeFalse(isShellTransitionsEnabled())
prevDevEnableNonResizableMultiWindow = getDevEnableNonResizableMultiWindow(context)
if (prevDevEnableNonResizableMultiWindow != 0) {
// Turn off the development option
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index 5061b23..284f384 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -97,7 +97,8 @@
// listen for addView
mAddWindowForTask = taskId;
mViewThemeResId = view.getContext().getThemeResId();
- return true;
+ // Do not wait for background color
+ return false;
}
@Override
diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp
index 1b8db46..3527eee 100644
--- a/libs/androidfw/CursorWindow.cpp
+++ b/libs/androidfw/CursorWindow.cpp
@@ -62,7 +62,6 @@
window->clear();
window->updateSlotsData();
- LOG(DEBUG) << "Created: " << window->toString();
*outWindow = window;
return OK;
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index b8fa55a..18fab8e 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -88,6 +88,9 @@
StretchEffectBehavior Properties::stretchEffectBehavior = StretchEffectBehavior::ShaderHWUI;
+bool Properties::drawingEnabled = true;
+OverrideDrawingEnabled Properties::overrideDrawingEnabled = OverrideDrawingEnabled::Default;
+
bool Properties::load() {
bool prevDebugLayersUpdates = debugLayersUpdates;
bool prevDebugOverdraw = debugOverdraw;
@@ -141,6 +144,11 @@
enableWebViewOverlays = base::GetBoolProperty(PROPERTY_WEBVIEW_OVERLAYS_ENABLED, false);
+ drawingEnabled = base::GetBoolProperty(PROPERTY_DRAWING_ENABLED, true);
+ if (!drawingEnabled) {
+ enableRTAnimations = false;
+ }
+
return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw);
}
@@ -210,5 +218,18 @@
sRenderPipelineType = type;
}
+void Properties::setDrawingEnabled(bool newDrawingEnabled) {
+ overrideDrawingEnabled =
+ newDrawingEnabled ? OverrideDrawingEnabled::On : OverrideDrawingEnabled::Off;
+ enableRTAnimations = newDrawingEnabled;
+}
+
+bool Properties::isDrawingEnabled() {
+ if (overrideDrawingEnabled == OverrideDrawingEnabled::Default) {
+ return drawingEnabled;
+ }
+ return overrideDrawingEnabled == OverrideDrawingEnabled::On;
+}
+
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 7df6e2c..73fccb6 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -187,6 +187,12 @@
*/
#define PROPERTY_WEBVIEW_OVERLAYS_ENABLED "debug.hwui.webview_overlays_enabled"
+/**
+ * Property for globally GL drawing state. Can be overridden per process with
+ * setDrawingEnabled.
+ */
+#define PROPERTY_DRAWING_ENABLED "debug.hwui.drawing_enabled"
+
///////////////////////////////////////////////////////////////////////////////
// Misc
///////////////////////////////////////////////////////////////////////////////
@@ -208,6 +214,8 @@
UniformScale // Uniform scale stretch everywhere
};
+enum class OverrideDrawingEnabled { Default, On, Off };
+
/**
* Renderthread-only singleton which manages several static rendering properties. Most of these
* are driven by system properties which are queried once at initialization, and again if init()
@@ -301,6 +309,12 @@
stretchEffectBehavior = behavior;
}
+ // Represents if GL drawing is enabled. Should only be false in headless testing environments
+ static bool drawingEnabled;
+ static OverrideDrawingEnabled overrideDrawingEnabled;
+ static bool isDrawingEnabled();
+ static void setDrawingEnabled(bool enable);
+
private:
static StretchEffectBehavior stretchEffectBehavior;
static ProfileType sProfileType;
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index d8735ce..a743d30 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -183,8 +183,10 @@
SkPaint paint;
paint.setAlpha(255);
paint.setBlendMode(SkBlendMode::kSrc);
- canvas->drawImageRect(image, imageSrcRect, imageDstRect, sampling, &paint,
- SkCanvas::kFast_SrcRectConstraint);
+ const bool hasBufferCrop = cropRect.left < cropRect.right && cropRect.top < cropRect.bottom;
+ auto constraint =
+ hasBufferCrop ? SkCanvas::kStrict_SrcRectConstraint : SkCanvas::kFast_SrcRectConstraint;
+ canvas->drawImageRect(image, imageSrcRect, imageDstRect, sampling, &paint, constraint);
canvas->restore();
if (!tmpSurface->readPixels(*bitmap, 0, 0)) {
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 442ae0f..c945f27 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -15,6 +15,7 @@
*/
#include "RecordingCanvas.h"
+#include <hwui/Paint.h>
#include <GrRecordingContext.h>
@@ -495,7 +496,7 @@
sp<VectorDrawableRoot> mRoot;
SkRect mBounds;
- SkPaint paint;
+ Paint paint;
BitmapPalette palette;
};
@@ -833,7 +834,8 @@
// TODO: We should be const. Or not. Or just use a different map
// Unclear, but this is the quick fix
const T* op = reinterpret_cast<const T*>(opRaw);
- transformPaint(transform, const_cast<SkPaint*>(&(op->paint)), op->palette);
+ const SkPaint* paint = &op->paint;
+ transformPaint(transform, const_cast<SkPaint*>(paint), op->palette);
};
}
else if
@@ -842,7 +844,8 @@
// TODO: We should be const. Or not. Or just use a different map
// Unclear, but this is the quick fix
const T* op = reinterpret_cast<const T*>(opRaw);
- transformPaint(transform, const_cast<SkPaint*>(&(op->paint)));
+ const SkPaint* paint = &op->paint;
+ transformPaint(transform, const_cast<SkPaint*>(paint));
};
}
else {
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index d032e2b..d6b6e16 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -182,7 +182,7 @@
return SkAndroidFrameworkUtils::SaveBehind(mCanvas, &bounds);
}
-void SkiaCanvas::restoreUnclippedLayer(int restoreCount, const SkPaint& paint) {
+void SkiaCanvas::restoreUnclippedLayer(int restoreCount, const Paint& paint) {
while (mCanvas->getSaveCount() > restoreCount + 1) {
this->restore();
@@ -439,13 +439,13 @@
mCanvas->drawColor(color, mode);
}
-void SkiaCanvas::onFilterPaint(SkPaint& paint) {
+void SkiaCanvas::onFilterPaint(Paint& paint) {
if (mPaintFilter) {
- mPaintFilter->filter(&paint);
+ mPaintFilter->filterFullPaint(&paint);
}
}
-void SkiaCanvas::drawPaint(const SkPaint& paint) {
+void SkiaCanvas::drawPaint(const Paint& paint) {
mCanvas->drawPaint(filterPaint(paint));
}
@@ -552,9 +552,8 @@
void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
auto image = bitmap.makeImage();
- applyLooper(paint, [&](const SkPaint& p) {
- auto sampling = SkSamplingOptions(p.getFilterQuality());
- mCanvas->drawImage(image, left, top, sampling, &p);
+ applyLooper(paint, [&](const Paint& p) {
+ mCanvas->drawImage(image, left, top, p.sampling(), &p);
});
}
@@ -562,9 +561,8 @@
auto image = bitmap.makeImage();
SkAutoCanvasRestore acr(mCanvas, true);
mCanvas->concat(matrix);
- applyLooper(paint, [&](const SkPaint& p) {
- auto sampling = SkSamplingOptions(p.getFilterQuality());
- mCanvas->drawImage(image, 0, 0, sampling, &p);
+ applyLooper(paint, [&](const Paint& p) {
+ mCanvas->drawImage(image, 0, 0, p.sampling(), &p);
});
}
@@ -575,18 +573,12 @@
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- applyLooper(paint, [&](const SkPaint& p) {
- auto sampling = SkSamplingOptions(p.getFilterQuality());
- mCanvas->drawImageRect(image, srcRect, dstRect, sampling, &p,
+ applyLooper(paint, [&](const Paint& p) {
+ mCanvas->drawImageRect(image, srcRect, dstRect, p.sampling(), &p,
SkCanvas::kFast_SrcRectConstraint);
});
}
-static SkFilterMode paintToFilter(const Paint* paint) {
- return paint && paint->isFilterBitmap() ? SkFilterMode::kLinear
- : SkFilterMode::kNearest;
-}
-
void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const Paint* paint) {
const int ptCount = (meshWidth + 1) * (meshHeight + 1);
@@ -668,13 +660,13 @@
if (paint) {
pnt = *paint;
}
- SkSamplingOptions sampling(paintToFilter(&pnt));
+ SkSamplingOptions sampling = pnt.sampling();
pnt.setShader(image->makeShader(sampling));
auto v = builder.detach();
- applyLooper(&pnt, [&](const SkPaint& p) {
+ applyLooper(&pnt, [&](const Paint& p) {
SkPaint copy(p);
- auto s = SkSamplingOptions(p.getFilterQuality());
+ auto s = p.sampling();
if (s != sampling) {
// applyLooper changed the quality?
copy.setShader(image->makeShader(s));
@@ -707,9 +699,8 @@
lattice.fBounds = nullptr;
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
auto image = bitmap.makeImage();
- applyLooper(paint, [&](const SkPaint& p) {
- auto filter = SkSamplingOptions(p.getFilterQuality()).filter;
- mCanvas->drawImageLattice(image.get(), lattice, dst, filter, &p);
+ applyLooper(paint, [&](const Paint& p) {
+ mCanvas->drawImageLattice(image.get(), lattice, dst, p.filterMode(), &p);
});
}
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 438a40c..fd6bbdc 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -23,6 +23,7 @@
#include "VectorDrawable.h"
#include "hwui/Canvas.h"
#include "hwui/Paint.h"
+#include "hwui/BlurDrawLooper.h"
#include <SkCanvas.h>
#include "pipeline/skia/AnimatedDrawables.h"
@@ -73,7 +74,7 @@
virtual int save(SaveFlags::Flags flags) override;
virtual void restore() override;
virtual void restoreToCount(int saveCount) override;
- virtual void restoreUnclippedLayer(int saveCount, const SkPaint& paint) override;
+ virtual void restoreUnclippedLayer(int saveCount, const Paint& paint) override;
virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint) override;
virtual int saveLayerAlpha(float left, float top, float right, float bottom, int alpha) override;
@@ -99,7 +100,7 @@
virtual SkCanvasState* captureCanvasState() const override;
virtual void drawColor(int color, SkBlendMode mode) override;
- virtual void drawPaint(const SkPaint& paint) override;
+ virtual void drawPaint(const Paint& paint) override;
virtual void drawPoint(float x, float y, const Paint& paint) override;
virtual void drawPoints(const float* points, int count, const Paint& paint) override;
@@ -167,10 +168,10 @@
const Paint& paint, const SkPath& path, size_t start,
size_t end) override;
- void onFilterPaint(SkPaint& paint);
+ void onFilterPaint(Paint& paint);
- SkPaint filterPaint(const SkPaint& src) {
- SkPaint dst(src);
+ Paint filterPaint(const Paint& src) {
+ Paint dst(src);
this->onFilterPaint(dst);
return dst;
}
@@ -179,21 +180,20 @@
template <typename Proc>
void applyLooper(const Paint* paint, Proc proc, void (*preFilter)(SkPaint&) = nullptr) {
BlurDrawLooper* looper = paint ? paint->getLooper() : nullptr;
- const SkPaint* skpPtr = paint;
- SkPaint skp = skpPtr ? *skpPtr : SkPaint();
+ Paint pnt = paint ? *paint : Paint();
if (preFilter) {
- preFilter(skp);
+ preFilter(pnt);
}
- this->onFilterPaint(skp);
+ this->onFilterPaint(pnt);
if (looper) {
- looper->apply(skp, [&](SkPoint offset, const SkPaint& modifiedPaint) {
+ looper->apply(pnt, [&](SkPoint offset, const Paint& modifiedPaint) {
mCanvas->save();
mCanvas->translate(offset.fX, offset.fY);
proc(modifiedPaint);
mCanvas->restore();
});
} else {
- proc(skp);
+ proc(pnt);
}
}
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 55f434f..f116641 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -463,10 +463,10 @@
mStagingCache.dirty = false;
}
- SkPaint skp;
+ Paint skp;
getPaintFor(&skp, mStagingProperties);
Paint paint;
- paint.setFilterQuality(skp.getFilterQuality());
+ paint.setFilterBitmap(skp.isFilterBitmap());
paint.setColorFilter(skp.refColorFilter());
paint.setAlpha(skp.getAlpha());
outCanvas->drawBitmap(*mStagingCache.bitmap, 0, 0, mStagingCache.bitmap->width(),
@@ -476,9 +476,9 @@
mStagingProperties.getBounds().bottom(), &paint);
}
-void Tree::getPaintFor(SkPaint* outPaint, const TreeProperties& prop) const {
+void Tree::getPaintFor(Paint* outPaint, const TreeProperties& prop) const {
// HWUI always draws VD with bilinear filtering.
- outPaint->setFilterQuality(kLow_SkFilterQuality);
+ outPaint->setFilterBitmap(true);
if (prop.getColorFilter() != nullptr) {
outPaint->setColorFilter(sk_ref_sp(prop.getColorFilter()));
}
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index ac7d41e..30bb04a 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -648,7 +648,7 @@
*/
void draw(SkCanvas* canvas, const SkRect& bounds, const SkPaint& paint);
- void getPaintFor(SkPaint* outPaint, const TreeProperties &props) const;
+ void getPaintFor(Paint* outPaint, const TreeProperties &props) const;
BitmapPalette computePalette();
void setAntiAlias(bool aa) { mRootNode->setAntiAlias(aa); }
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
index 876f5c8..d08bc5c5 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.cpp
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -157,7 +157,6 @@
lazyPaint.emplace();
lazyPaint->setAlpha(mProperties.mAlpha);
lazyPaint->setColorFilter(mProperties.mColorFilter);
- lazyPaint->setFilterQuality(kLow_SkFilterQuality);
}
canvas->concat(matrix);
diff --git a/libs/hwui/hwui/BlurDrawLooper.cpp b/libs/hwui/hwui/BlurDrawLooper.cpp
index 27a038d..270d24a 100644
--- a/libs/hwui/hwui/BlurDrawLooper.cpp
+++ b/libs/hwui/hwui/BlurDrawLooper.cpp
@@ -24,7 +24,7 @@
BlurDrawLooper::~BlurDrawLooper() = default;
-SkPoint BlurDrawLooper::apply(SkPaint* paint) const {
+SkPoint BlurDrawLooper::apply(Paint* paint) const {
paint->setColor(mColor);
if (mBlurSigma > 0) {
paint->setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, mBlurSigma, true));
diff --git a/libs/hwui/hwui/BlurDrawLooper.h b/libs/hwui/hwui/BlurDrawLooper.h
index 7e6786f..09a4e0f 100644
--- a/libs/hwui/hwui/BlurDrawLooper.h
+++ b/libs/hwui/hwui/BlurDrawLooper.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_GRAPHICS_BLURDRAWLOOPER_H_
#define ANDROID_GRAPHICS_BLURDRAWLOOPER_H_
-#include <SkPaint.h>
+#include <hwui/Paint.h>
#include <SkRefCnt.h>
class SkColorSpace;
@@ -30,10 +30,10 @@
~BlurDrawLooper() override;
- // proc(SkPoint offset, const SkPaint& modifiedPaint)
+ // proc(SkPoint offset, const Paint& modifiedPaint)
template <typename DrawProc>
- void apply(const SkPaint& paint, DrawProc proc) const {
- SkPaint p(paint);
+ void apply(const Paint& paint, DrawProc proc) const {
+ Paint p(paint);
proc(this->apply(&p), p); // draw the shadow
proc({0, 0}, paint); // draw the original (on top)
}
@@ -43,7 +43,7 @@
const float mBlurSigma;
const SkPoint mOffset;
- SkPoint apply(SkPaint* paint) const;
+ SkPoint apply(Paint* paint) const;
BlurDrawLooper(SkColor4f, float, SkPoint);
};
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 9023613..70a558b 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -162,7 +162,7 @@
virtual int save(SaveFlags::Flags flags) = 0;
virtual void restore() = 0;
virtual void restoreToCount(int saveCount) = 0;
- virtual void restoreUnclippedLayer(int saveCount, const SkPaint& paint) = 0;
+ virtual void restoreUnclippedLayer(int saveCount, const Paint& paint) = 0;
virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint) = 0;
virtual int saveLayerAlpha(float left, float top, float right, float bottom, int alpha) = 0;
@@ -197,7 +197,7 @@
// Canvas draw operations
// ----------------------------------------------------------------------------
virtual void drawColor(int color, SkBlendMode mode) = 0;
- virtual void drawPaint(const SkPaint& paint) = 0;
+ virtual void drawPaint(const Paint& paint) = 0;
// Geometry
virtual void drawPoint(float x, float y, const Paint& paint) = 0;
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
index 5d9fad5..fc542c8 100644
--- a/libs/hwui/hwui/ImageDecoder.cpp
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -24,7 +24,6 @@
#include <SkBlendMode.h>
#include <SkCanvas.h>
#include <SkEncodedOrigin.h>
-#include <SkFilterQuality.h>
#include <SkPaint.h>
#undef LOG_TAG
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index d9c9eee..4a8f3e1 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -17,13 +17,13 @@
#ifndef ANDROID_GRAPHICS_PAINT_H_
#define ANDROID_GRAPHICS_PAINT_H_
-#include "BlurDrawLooper.h"
#include "Typeface.h"
#include <cutils/compiler.h>
#include <SkFont.h>
#include <SkPaint.h>
+#include <SkSamplingOptions.h>
#include <string>
#include <minikin/FontFamily.h>
@@ -32,6 +32,8 @@
namespace android {
+class BlurDrawLooper;
+
class Paint : public SkPaint {
public:
// Default values for underlined and strikethrough text,
@@ -60,7 +62,7 @@
const SkFont& getSkFont() const { return mFont; }
BlurDrawLooper* getLooper() const { return mLooper.get(); }
- void setLooper(sk_sp<BlurDrawLooper> looper) { mLooper = std::move(looper); }
+ void setLooper(sk_sp<BlurDrawLooper> looper);
// These shadow the methods on SkPaint, but we need to so we can keep related
// attributes in-sync.
@@ -138,7 +140,15 @@
void setDevKern(bool d) { mDevKern = d; }
// Deprecated -- bitmapshaders will be taking this flag explicitly
- bool isFilterBitmap() const { return this->getFilterQuality() != kNone_SkFilterQuality; }
+ bool isFilterBitmap() const { return mFilterBitmap; }
+ void setFilterBitmap(bool filter) { mFilterBitmap = filter; }
+
+ SkFilterMode filterMode() const {
+ return mFilterBitmap ? SkFilterMode::kLinear : SkFilterMode::kNearest;
+ }
+ SkSamplingOptions sampling() const {
+ return SkSamplingOptions(this->filterMode());
+ }
// The Java flags (Paint.java) no longer fit into the native apis directly.
// These methods handle converting to and from them and the native representations
@@ -169,6 +179,7 @@
// nullptr is valid: it means the default typeface.
const Typeface* mTypeface = nullptr;
Align mAlign = kLeft_Align;
+ bool mFilterBitmap = false;
bool mStrikeThru = false;
bool mUnderline = false;
bool mDevKern = false;
diff --git a/libs/hwui/hwui/PaintFilter.h b/libs/hwui/hwui/PaintFilter.h
index 0e7b619..4996aa4 100644
--- a/libs/hwui/hwui/PaintFilter.h
+++ b/libs/hwui/hwui/PaintFilter.h
@@ -1,17 +1,18 @@
#ifndef ANDROID_GRAPHICS_PAINT_FILTER_H_
#define ANDROID_GRAPHICS_PAINT_FILTER_H_
-class SkPaint;
+#include <SkRefCnt.h>
namespace android {
+class Paint;
+
class PaintFilter : public SkRefCnt {
public:
/**
* Called with the paint that will be used to draw.
* The implementation may modify the paint as they wish.
*/
- virtual void filter(SkPaint*) = 0;
virtual void filterFullPaint(Paint*) = 0;
};
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index fa2674f..aac928f 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -15,6 +15,7 @@
*/
#include "Paint.h"
+#include "BlurDrawLooper.h"
namespace android {
@@ -43,6 +44,7 @@
, mHyphenEdit(paint.mHyphenEdit)
, mTypeface(paint.mTypeface)
, mAlign(paint.mAlign)
+ , mFilterBitmap(paint.mFilterBitmap)
, mStrikeThru(paint.mStrikeThru)
, mUnderline(paint.mUnderline)
, mDevKern(paint.mDevKern) {}
@@ -62,6 +64,7 @@
mHyphenEdit = other.mHyphenEdit;
mTypeface = other.mTypeface;
mAlign = other.mAlign;
+ mFilterBitmap = other.mFilterBitmap;
mStrikeThru = other.mStrikeThru;
mUnderline = other.mUnderline;
mDevKern = other.mDevKern;
@@ -77,6 +80,7 @@
a.mMinikinLocaleListId == b.mMinikinLocaleListId &&
a.mFamilyVariant == b.mFamilyVariant && a.mHyphenEdit == b.mHyphenEdit &&
a.mTypeface == b.mTypeface && a.mAlign == b.mAlign &&
+ a.mFilterBitmap == b.mFilterBitmap &&
a.mStrikeThru == b.mStrikeThru && a.mUnderline == b.mUnderline &&
a.mDevKern == b.mDevKern;
}
@@ -88,11 +92,16 @@
mFont.setEdging(SkFont::Edging::kAlias);
mLooper.reset();
+ mFilterBitmap = false;
mStrikeThru = false;
mUnderline = false;
mDevKern = false;
}
+void Paint::setLooper(sk_sp<BlurDrawLooper> looper) {
+ mLooper = std::move(looper);
+}
+
void Paint::setAntiAlias(bool aa) {
// Java does not support/understand subpixel(lcd) antialiasing
SkASSERT(mFont.getEdging() != SkFont::Edging::kSubpixelAntiAlias);
@@ -131,9 +140,6 @@
uint32_t flags = 0;
flags |= -(int)paint.isAntiAlias() & sAntiAliasFlag;
flags |= -(int)paint.isDither() & sDitherFlag;
- if (paint.getFilterQuality() != kNone_SkFilterQuality) {
- flags |= sFilterBitmapFlag;
- }
return flags;
}
@@ -150,12 +156,6 @@
static void applyLegacyFlagsToPaint(uint32_t flags, SkPaint* paint) {
paint->setAntiAlias((flags & sAntiAliasFlag) != 0);
paint->setDither ((flags & sDitherFlag) != 0);
-
- if (flags & sFilterBitmapFlag) {
- paint->setFilterQuality(kLow_SkFilterQuality);
- } else {
- paint->setFilterQuality(kNone_SkFilterQuality);
- }
}
static void applyLegacyFlagsToFont(uint32_t flags, SkFont* font) {
@@ -182,18 +182,20 @@
uint32_t Paint::getJavaFlags() const {
uint32_t flags = paintToLegacyFlags(*this) | fontToLegacyFlags(mFont);
- flags |= -(int)mStrikeThru & sStrikeThruFlag;
- flags |= -(int)mUnderline & sUnderlineFlag;
- flags |= -(int)mDevKern & sDevKernFlag;
+ flags |= -(int)mStrikeThru & sStrikeThruFlag;
+ flags |= -(int)mUnderline & sUnderlineFlag;
+ flags |= -(int)mDevKern & sDevKernFlag;
+ flags |= -(int)mFilterBitmap & sFilterBitmapFlag;
return flags;
}
void Paint::setJavaFlags(uint32_t flags) {
applyLegacyFlagsToPaint(flags, this);
applyLegacyFlagsToFont(flags, &mFont);
- mStrikeThru = (flags & sStrikeThruFlag) != 0;
- mUnderline = (flags & sUnderlineFlag) != 0;
- mDevKern = (flags & sDevKernFlag) != 0;
+ mStrikeThru = (flags & sStrikeThruFlag) != 0;
+ mUnderline = (flags & sUnderlineFlag) != 0;
+ mDevKern = (flags & sDevKernFlag) != 0;
+ mFilterBitmap = (flags & sFilterBitmapFlag) != 0;
}
} // namespace android
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index bcec0fa..22a1e1f 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -663,8 +663,7 @@
}
static void setFilterBitmap(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle, jboolean filterBitmap) {
- reinterpret_cast<Paint*>(paintHandle)->setFilterQuality(
- filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality);
+ reinterpret_cast<Paint*>(paintHandle)->setFilterBitmap(filterBitmap);
}
static void setDither(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle, jboolean dither) {
diff --git a/libs/hwui/jni/PaintFilter.cpp b/libs/hwui/jni/PaintFilter.cpp
index ec115b4..c30e29b 100644
--- a/libs/hwui/jni/PaintFilter.cpp
+++ b/libs/hwui/jni/PaintFilter.cpp
@@ -29,10 +29,6 @@
fClearFlags = static_cast<uint16_t>(clearFlags);
fSetFlags = static_cast<uint16_t>(setFlags);
}
- void filter(SkPaint* paint) override {
- uint32_t flags = Paint::GetSkPaintJavaFlags(*paint);
- Paint::SetSkPaintJavaFlags(paint, (flags & ~fClearFlags) | fSetFlags);
- }
void filterFullPaint(Paint* paint) override {
paint->setJavaFlags((paint->getJavaFlags() & ~fClearFlags) | fSetFlags);
}
diff --git a/libs/hwui/jni/Utils.cpp b/libs/hwui/jni/Utils.cpp
index ac2f5b7..1259bb5 100644
--- a/libs/hwui/jni/Utils.cpp
+++ b/libs/hwui/jni/Utils.cpp
@@ -18,6 +18,7 @@
#include "SkUtils.h"
#include "SkData.h"
+#include <inttypes.h>
#include <log/log.h>
using namespace android;
@@ -76,7 +77,7 @@
bool AssetStreamAdaptor::move(long offset) {
if (fAsset->seek(offset, SEEK_CUR) == -1) {
- SkDebugf("---- fAsset->seek(%i, SEEK_CUR) failed\n", offset);
+ SkDebugf("---- fAsset->seek(%li, SEEK_CUR) failed\n", offset);
return false;
}
@@ -100,7 +101,7 @@
}
off64_t newOffset = fAsset->seek(size, SEEK_CUR);
if (-1 == newOffset) {
- SkDebugf("---- fAsset->seek(%d) failed\n", size);
+ SkDebugf("---- fAsset->seek(%zu) failed\n", size);
return 0;
}
amount = newOffset - oldOffset;
@@ -127,14 +128,14 @@
const off64_t size = asset->getLength();
if (size <= 0) {
- SkDebugf("---- copyAsset: asset->getLength() returned %d\n", size);
+ SkDebugf("---- copyAsset: asset->getLength() returned %" PRId64 "\n", size);
return NULL;
}
sk_sp<SkData> data(SkData::MakeUninitialized(size));
const off64_t len = asset->read(data->writable_data(), size);
if (len != size) {
- SkDebugf("---- copyAsset: asset->read(%d) returned %d\n", size, len);
+ SkDebugf("---- copyAsset: asset->read(%" PRId64 ") returned %" PRId64 "\n", size, len);
return NULL;
}
diff --git a/libs/hwui/jni/android_graphics_Canvas.cpp b/libs/hwui/jni/android_graphics_Canvas.cpp
index a611f7c..dada5ae9 100644
--- a/libs/hwui/jni/android_graphics_Canvas.cpp
+++ b/libs/hwui/jni/android_graphics_Canvas.cpp
@@ -233,7 +233,7 @@
jlong colorLong, jint modeHandle) {
SkColor4f color = GraphicsJNI::convertColorLong(colorLong);
sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
- SkPaint p;
+ Paint p;
p.setColor4f(color, cs.get());
SkBlendMode mode = static_cast<SkBlendMode>(modeHandle);
@@ -421,7 +421,7 @@
if (paint) {
filteredPaint = *paint;
}
- filteredPaint.setFilterQuality(kLow_SkFilterQuality);
+ filteredPaint.setFilterBitmap(true);
canvas->drawNinePatch(bitmap, *chunk, 0, 0, (right-left)/scale, (bottom-top)/scale,
&filteredPaint);
@@ -443,7 +443,7 @@
if (paint) {
filteredPaint = *paint;
}
- filteredPaint.setFilterQuality(kLow_SkFilterQuality);
+ filteredPaint.setFilterBitmap(true);
canvas->drawBitmap(bitmap, left, top, &filteredPaint);
} else {
canvas->drawBitmap(bitmap, left, top, paint);
@@ -458,7 +458,7 @@
if (paint) {
filteredPaint = *paint;
}
- filteredPaint.setFilterQuality(kLow_SkFilterQuality);
+ filteredPaint.setFilterBitmap(true);
canvas->drawBitmap(bitmap, 0, 0, &filteredPaint);
canvas->restore();
@@ -486,7 +486,7 @@
if (paint) {
filteredPaint = *paint;
}
- filteredPaint.setFilterQuality(kLow_SkFilterQuality);
+ filteredPaint.setFilterBitmap(true);
canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
dstLeft, dstTop, dstRight, dstBottom, &filteredPaint);
} else {
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index ef3a11c..78f6779 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -896,6 +896,14 @@
DeviceInfo::setPresentationDeadlineNanos(presentationDeadlineNanos);
}
+static void android_view_ThreadedRenderer_setDrawingEnabled(JNIEnv*, jclass, jboolean enabled) {
+ Properties::setDrawingEnabled(enabled);
+}
+
+static jboolean android_view_ThreadedRenderer_isDrawingEnabled(JNIEnv*, jclass) {
+ return Properties::isDrawingEnabled();
+}
+
// ----------------------------------------------------------------------------
// HardwareRendererObserver
// ----------------------------------------------------------------------------
@@ -1032,6 +1040,8 @@
{"preload", "()V", (void*)android_view_ThreadedRenderer_preload},
{"isWebViewOverlaysEnabled", "()Z",
(void*)android_view_ThreadedRenderer_isWebViewOverlaysEnabled},
+ {"nSetDrawingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDrawingEnabled},
+ {"nIsDrawingEnabled", "()Z", (void*)android_view_ThreadedRenderer_isDrawingEnabled},
};
static JavaVM* mJvm = nullptr;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 7b962cc..9c51e62 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -192,23 +192,13 @@
}
}
-static SkFilterMode Paint_to_filter(const SkPaint& paint) {
- return paint.getFilterQuality() != kNone_SkFilterQuality ? SkFilterMode::kLinear
- : SkFilterMode::kNearest;
-}
-
-static SkSamplingOptions Paint_to_sampling(const SkPaint& paint) {
- // Android only has 1-bit for "filter", so we don't try to cons-up mipmaps or cubics
- return SkSamplingOptions(Paint_to_filter(paint), SkMipmapMode::kNone);
-}
-
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
sk_sp<SkImage> image = bitmap.makeImage();
applyLooper(
paint,
- [&](const SkPaint& p) {
- mRecorder.drawImage(image, left, top, Paint_to_sampling(p), &p, bitmap.palette());
+ [&](const Paint& p) {
+ mRecorder.drawImage(image, left, top, p.sampling(), &p, bitmap.palette());
},
FilterForImage);
@@ -228,8 +218,8 @@
applyLooper(
paint,
- [&](const SkPaint& p) {
- mRecorder.drawImage(image, 0, 0, Paint_to_sampling(p), &p, bitmap.palette());
+ [&](const Paint& p) {
+ mRecorder.drawImage(image, 0, 0, p.sampling(), &p, bitmap.palette());
},
FilterForImage);
@@ -248,8 +238,8 @@
applyLooper(
paint,
- [&](const SkPaint& p) {
- mRecorder.drawImageRect(image, srcRect, dstRect, Paint_to_sampling(p), &p,
+ [&](const Paint& p) {
+ mRecorder.drawImageRect(image, srcRect, dstRect, p.sampling(), &p,
SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
},
FilterForImage);
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 025be7b..ab9d0b2 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -256,7 +256,7 @@
}
void CanvasContext::allocateBuffers() {
- if (mNativeSurface) {
+ if (mNativeSurface && Properties::isDrawingEnabled()) {
ANativeWindow_tryAllocateBuffers(mNativeSurface->getNativeWindow());
}
}
@@ -480,7 +480,8 @@
SkRect dirty;
mDamageAccumulator.finish(&dirty);
- if (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw()) {
+ if (!Properties::isDrawingEnabled() ||
+ (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw())) {
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
// Notify the callbacks, even if there's nothing to draw so they aren't waiting
// indefinitely
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 6dbfcc3..2fed468 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -90,9 +90,17 @@
* and false otherwise (e.g. cache limits have been exceeded).
*/
bool pinImages(std::vector<SkImage*>& mutableImages) {
+ if (!Properties::isDrawingEnabled()) {
+ return true;
+ }
return mRenderPipeline->pinImages(mutableImages);
}
- bool pinImages(LsaVector<sk_sp<Bitmap>>& images) { return mRenderPipeline->pinImages(images); }
+ bool pinImages(LsaVector<sk_sp<Bitmap>>& images) {
+ if (!Properties::isDrawingEnabled()) {
+ return true;
+ }
+ return mRenderPipeline->pinImages(images);
+ }
/**
* Unpin any image that had be previously pinned to the GPU cache
diff --git a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
index 10ba079..31a8ae1 100644
--- a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
@@ -49,7 +49,7 @@
paint.setAntiAlias(true);
paint.setColor(Color::Green_700);
canvas.drawCircle(200, 200, 200, paint);
- SkPaint alphaPaint;
+ Paint alphaPaint;
alphaPaint.setAlpha(128);
canvas.restoreUnclippedLayer(unclippedSaveLayer, alphaPaint);
canvas.restore();
diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index a1ba70a..dc1b2e6 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -61,11 +61,11 @@
TEST(SkiaBehavior, porterDuffCreateIsCached) {
SkPaint paint;
paint.setBlendMode(SkBlendMode::kOverlay);
- auto expected = paint.getBlendMode();
+ auto expected = paint.asBlendMode();
paint.setBlendMode(SkBlendMode::kClear);
- ASSERT_NE(expected, paint.getBlendMode());
+ ASSERT_NE(expected, paint.asBlendMode());
paint.setBlendMode(SkBlendMode::kOverlay);
- ASSERT_EQ(expected, paint.getBlendMode());
+ ASSERT_EQ(expected, paint.asBlendMode());
}
TEST(SkiaBehavior, pathIntersection) {
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
index f0fb068..94bcb11 100644
--- a/libs/hwui/utils/PaintUtils.h
+++ b/libs/hwui/utils/PaintUtils.h
@@ -32,13 +32,6 @@
*/
class PaintUtils {
public:
- static inline GLenum getFilter(const SkPaint* paint) {
- if (!paint || paint->getFilterQuality() != kNone_SkFilterQuality) {
- return GL_LINEAR;
- }
- return GL_NEAREST;
- }
-
static bool isOpaquePaint(const SkPaint* paint) {
if (!paint) return true; // default (paintless) behavior is SrcOver, black
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 93a5444..693a027 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -44,70 +44,14 @@
LOG_ALWAYS_FATAL_IF(!static_cast<const Rect&>(name).isValid(), \
"invalid arg passed as " #name " argument");
-static bool getWideColorSupport(const sp<SurfaceControl>& surfaceControl) {
- sp<SurfaceComposerClient> client = surfaceControl->getClient();
-
- const sp<IBinder> display = client->getInternalDisplayToken();
- if (display == nullptr) {
- ALOGE("unable to get wide color support for disconnected internal display");
- return false;
- }
-
- bool isWideColorDisplay = false;
- status_t err = client->isWideColorDisplay(display, &isWideColorDisplay);
- if (err) {
- ALOGE("unable to get wide color support");
- return false;
- }
- return isWideColorDisplay;
-}
-
-static bool getHdrSupport(const sp<SurfaceControl>& surfaceControl) {
- sp<SurfaceComposerClient> client = surfaceControl->getClient();
-
- const sp<IBinder> display = client->getInternalDisplayToken();
- if (display == nullptr) {
- ALOGE("unable to get hdr capabilities for disconnected internal display");
- return false;
- }
-
- ui::DynamicDisplayInfo info;
- if (status_t err = client->getDynamicDisplayInfo(display, &info); err != NO_ERROR) {
- ALOGE("unable to get hdr capabilities");
- return err;
- }
-
- return !info.hdrCapabilities.getSupportedHdrTypes().empty();
-}
-
-static bool isDataSpaceValid(const sp<SurfaceControl>& surfaceControl, ADataSpace dataSpace) {
- static_assert(static_cast<int>(ADATASPACE_UNKNOWN) == static_cast<int>(HAL_DATASPACE_UNKNOWN));
- static_assert(static_cast<int>(ADATASPACE_SCRGB_LINEAR) == static_cast<int>(HAL_DATASPACE_V0_SCRGB_LINEAR));
- static_assert(static_cast<int>(ADATASPACE_SRGB) == static_cast<int>(HAL_DATASPACE_V0_SRGB));
- static_assert(static_cast<int>(ADATASPACE_SCRGB) == static_cast<int>(HAL_DATASPACE_V0_SCRGB));
- static_assert(static_cast<int>(ADATASPACE_DISPLAY_P3) == static_cast<int>(HAL_DATASPACE_DISPLAY_P3));
- static_assert(static_cast<int>(ADATASPACE_BT2020_PQ) == static_cast<int>(HAL_DATASPACE_BT2020_PQ));
-
- switch (static_cast<android_dataspace_t>(dataSpace)) {
- case HAL_DATASPACE_UNKNOWN:
- case HAL_DATASPACE_V0_SRGB:
- return true;
- // These data space need wide gamut support.
- case HAL_DATASPACE_V0_SCRGB_LINEAR:
- case HAL_DATASPACE_V0_SCRGB:
- case HAL_DATASPACE_DISPLAY_P3:
- return getWideColorSupport(surfaceControl);
- // These data space need HDR support.
- case HAL_DATASPACE_BT2020_PQ:
- if (!getHdrSupport(surfaceControl)) {
- ALOGE("Invalid dataspace - device does not support hdr");
- return false;
- }
- return true;
- default:
- return false;
- }
-}
+static_assert(static_cast<int>(ADATASPACE_UNKNOWN) == static_cast<int>(HAL_DATASPACE_UNKNOWN));
+static_assert(static_cast<int>(ADATASPACE_SCRGB_LINEAR) ==
+ static_cast<int>(HAL_DATASPACE_V0_SCRGB_LINEAR));
+static_assert(static_cast<int>(ADATASPACE_SRGB) == static_cast<int>(HAL_DATASPACE_V0_SRGB));
+static_assert(static_cast<int>(ADATASPACE_SCRGB) == static_cast<int>(HAL_DATASPACE_V0_SCRGB));
+static_assert(static_cast<int>(ADATASPACE_DISPLAY_P3) ==
+ static_cast<int>(HAL_DATASPACE_DISPLAY_P3));
+static_assert(static_cast<int>(ADATASPACE_BT2020_PQ) == static_cast<int>(HAL_DATASPACE_BT2020_PQ));
Transaction* ASurfaceTransaction_to_Transaction(ASurfaceTransaction* aSurfaceTransaction) {
return reinterpret_cast<Transaction*>(aSurfaceTransaction);
@@ -580,10 +524,6 @@
CHECK_NOT_NULL(aSurfaceControl);
sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
- if (!isDataSpaceValid(surfaceControl, aDataSpace)) {
- ALOGE("Failed to set buffer dataspace - invalid dataspace");
- return;
- }
Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
transaction->setDataspace(surfaceControl, static_cast<ui::Dataspace>(aDataSpace));
}
@@ -650,10 +590,6 @@
CHECK_NOT_NULL(aSurfaceControl);
sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
- if (!isDataSpaceValid(surfaceControl, dataspace)) {
- ALOGE("Failed to set buffer dataspace - invalid dataspace");
- return;
- }
Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
half3 color;
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 1581e24..54fb647 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -571,6 +571,10 @@
<!-- Permission required for GTS test - PendingSystemUpdateTest -->
<uses-permission android:name="android.permission.NOTIFY_PENDING_SYSTEM_UPDATE" />
+ <!-- Permission required to run the `vm` tool which manages on-device virtual machines -->
+ <uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
+ <uses-permission android:name="android.permission.DEBUG_VIRTUAL_MACHINE" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 8963dda..1b2aefc 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -451,6 +451,7 @@
<!-- started from SensoryPrivacyService -->
<activity android:name=".sensorprivacy.SensorUseStartedActivity"
android:exported="true"
+ android:launchMode="singleTop"
android:permission="android.permission.MANAGE_SENSOR_PRIVACY"
android:theme="@style/Theme.SystemUI.Dialog.Alert"
android:finishOnCloseSystemDialogs="true">
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 ac9298d..8505a62 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -16,7 +16,6 @@
import android.graphics.drawable.GradientDrawable
import android.os.Looper
import android.os.RemoteException
-import android.os.UserHandle
import android.util.Log
import android.util.MathUtils
import android.view.IRemoteAnimationFinishedCallback
@@ -32,19 +31,20 @@
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.wm.shell.startingsurface.SplashscreenContentDrawer
-import com.android.wm.shell.startingsurface.SplashscreenContentDrawer.SplashScreenWindowAttrs
+import com.android.wm.shell.startingsurface.StartingSurface
import kotlin.math.roundToInt
+private const val TAG = "ActivityLaunchAnimator"
+
/**
* A class that allows activities to be started in a seamless way from a view that is transforming
* nicely into the starting window.
*/
class ActivityLaunchAnimator(
private val keyguardHandler: KeyguardHandler,
+ private val startingSurface: StartingSurface?,
context: Context
) {
- private val TAG = this::class.java.simpleName
-
companion object {
const val ANIMATION_DURATION = 500L
private const val ANIMATION_DURATION_FADE_OUT_CONTENT = 150L
@@ -233,11 +233,21 @@
/**
* Return a [Controller] that will animate and expand [view] into the opening window.
*
- * Important: The view must be attached to the window when calling this function and
- * during the animation.
+ * Important: The view must be attached to a [ViewGroup] when calling this function and
+ * during the animation. For safety, this method will return null when it is not.
*/
@JvmStatic
- fun fromView(view: View, cujType: Int? = null): Controller {
+ fun fromView(view: View, cujType: Int? = null): Controller? {
+ if (view.parent !is ViewGroup) {
+ // TODO(b/192194319): Throw instead of just logging.
+ Log.wtf(
+ TAG,
+ "Skipping animation as view $view is not attached to a ViewGroup",
+ Exception()
+ )
+ return null
+ }
+
return GhostedViewLaunchAnimatorController(view, cujType)
}
}
@@ -474,7 +484,12 @@
// which is usually the same color of the app background. We first fade in this layer
// to hide the expanding view, then we fade it out with SRC mode to draw a hole in the
// launch container and reveal the opening window.
- val windowBackgroundColor = extractSplashScreenBackgroundColor(window)
+ val windowBackgroundColor = if (startingSurface != null) {
+ startingSurface.getBackgroundColor(window.taskInfo)
+ } else {
+ Log.w(TAG, "No starting surface, defaulting to SystemBGColor")
+ SplashscreenContentDrawer.getSystemBGColor()
+ }
val windowBackgroundLayer = GradientDrawable().apply {
setColor(windowBackgroundColor)
alpha = 0
@@ -553,36 +568,6 @@
animator.start()
}
- /** Extract the background color of the app splash screen. */
- private fun extractSplashScreenBackgroundColor(window: RemoteAnimationTarget): Int {
- val taskInfo = window.taskInfo
- val windowPackage = taskInfo.topActivity.packageName
- val userId = taskInfo.userId
- val windowContext = context.createPackageContextAsUser(
- windowPackage, Context.CONTEXT_RESTRICTED, UserHandle.of(userId))
- val activityInfo = taskInfo.topActivityInfo
- val splashScreenThemeName = packageManager.getSplashScreenTheme(windowPackage, userId)
- val splashScreenThemeId = if (splashScreenThemeName != null) {
- windowContext.resources.getIdentifier(splashScreenThemeName, null, null)
- } else {
- 0
- }
-
- val themeResId = when {
- splashScreenThemeId != 0 -> splashScreenThemeId
- activityInfo.themeResource != 0 -> activityInfo.themeResource
- else -> com.android.internal.R.style.Theme_DeviceDefault_DayNight
- }
-
- if (themeResId != windowContext.themeResId) {
- windowContext.setTheme(themeResId)
- }
-
- val windowAttrs = SplashScreenWindowAttrs()
- SplashscreenContentDrawer.getWindowAttrs(windowContext, windowAttrs)
- return SplashscreenContentDrawer.peekWindowBGColor(windowContext, windowAttrs)
- }
-
private fun applyStateToWindow(window: RemoteAnimationTarget, state: State) {
val screenBounds = window.screenSpaceBounds
val centerX = (screenBounds.left + screenBounds.right) / 2f
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
index ffb7ab4..b4ffb3f 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
@@ -9,6 +9,7 @@
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.InsetDrawable
import android.graphics.drawable.LayerDrawable
+import android.util.Log
import android.view.GhostView
import android.view.View
import android.view.ViewGroup
@@ -17,13 +18,15 @@
import com.android.internal.jank.InteractionJankMonitor
import kotlin.math.min
+private const val TAG = "GhostedViewLaunchAnimatorController"
+
/**
* A base implementation of [ActivityLaunchAnimator.Controller] which creates a [ghost][GhostView]
* of [ghostedView] as well as an expandable background view, which are drawn and animated instead
* of the ghosted view.
*
- * Important: [ghostedView] must be attached to the window when calling this function and during the
- * animation.
+ * Important: [ghostedView] must be attached to a [ViewGroup] when calling this function and during
+ * the animation.
*
* Note: Avoid instantiating this directly and call [ActivityLaunchAnimator.Controller.fromView]
* whenever possible instead.
@@ -113,6 +116,13 @@
}
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
+ if (ghostedView.parent !is ViewGroup) {
+ // This should usually not happen, but let's make sure we don't crash if the view was
+ // detached right before we started the animation.
+ Log.w(TAG, "Skipping animation as ghostedView is not attached to a ViewGroup")
+ return
+ }
+
backgroundView = FrameLayout(launchContainer.context)
launchContainerOverlay.add(backgroundView)
@@ -138,7 +148,7 @@
progress: Float,
linearProgress: Float
) {
- val ghostView = this.ghostView!!
+ val ghostView = this.ghostView ?: return
val backgroundView = this.backgroundView!!
if (!state.visible) {
@@ -173,6 +183,11 @@
}
override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
+ if (ghostView == null) {
+ // We didn't actually run the animation.
+ return
+ }
+
cujType?.let { InteractionJankMonitor.getInstance().end(it) }
backgroundDrawable?.wrapped?.alpha = startBackgroundAlpha
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java
index 95c2d2e..6d1408d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java
@@ -72,7 +72,8 @@
}
/**
- * @return if detail panel should animate when shown or closed
+ * Indicates whether the detail view wants to animate when shown. This has no affect over the
+ * closing animation. Detail panels will always animate when closed.
*/
default boolean shouldAnimate() {
return true;
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index c7a4829..ced155a 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -85,7 +85,7 @@
<string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Өтө көп графикалык ачкычты тартуу аракети болду"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN-кодуңузду <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Сырсөзүңүздү <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Кулпуну ачуучу графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Түзмөктү ачуучу графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM-картанын PIN-коду туура эмес. Эми түзмөктү бөгөттөн чыгаруу үчүн байланыш операторуңузга кайрылышыңыз керек."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
<item quantity="other">SIM-картанын PIN-коду туура эмес, сизде <xliff:g id="NUMBER_1">%d</xliff:g> аракет калды.</item>
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp-land/dimens.xml b/packages/SystemUI/res-keyguard/values-sw600dp-land/dimens.xml
index c34012d..d816b3a 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp-land/dimens.xml
@@ -21,4 +21,8 @@
<!-- Overload default clock widget parameters -->
<dimen name="widget_big_font_size">88dp</dimen>
+
+ <dimen name="qs_header_system_icons_area_height">0dp</dimen>
+ <dimen name="qs_panel_padding_top">0dp</dimen>
+
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/fp_to_unlock.xml b/packages/SystemUI/res/anim/fp_to_unlock.xml
new file mode 100644
index 0000000..a348208
--- /dev/null
+++ b/packages/SystemUI/res/anim/fp_to_unlock.xml
@@ -0,0 +1,171 @@
+<?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.
+-->
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android">
+ <aapt:attr name="android:drawable">
+ <vector android:height="65dp" android:width="46dp" android:viewportHeight="65" android:viewportWidth="46">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_1_G_N_7_T_0" android:translateX="-27" android:translateY="-17.5">
+ <group android:name="_R_G_L_1_G" android:translateX="30.75" android:translateY="25.75">
+ <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " />
+ <path android:name="_R_G_L_1_G_D_1_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " />
+ <path android:name="_R_G_L_1_G_D_2_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " />
+ <path android:name="_R_G_L_1_G_D_3_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " />
+ </group>
+ </group>
+ <group android:name="_R_G_L_0_G_N_7_T_0" android:translateX="-27" android:translateY="-17.5">
+ <group android:name="_R_G_L_0_G" android:translateX="47.357" android:translateY="53.25" android:pivotX="2.75" android:pivotY="2.75" android:scaleX="1.41866" android:scaleY="1.41866">
+ <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#b7f29f" android:fillAlpha="0" android:fillType="nonZero" android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c " />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="107" android:startOffset="0" android:valueFrom="M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " android:valueTo="M30.81 32.26 C30.56,32.49 30.27,38.76 29.96,38.9 C29.77,39.46 29.13,39.94 28.57,40.26 C28.15,40.51 26.93,40.65 26.4,40.65 C26.18,40.65 11.91,40.62 11.71,40.58 C10.68,40.53 9.06,39.79 8.89,38.88 C8.6,38.74 8.34,32.48 8.1,32.27 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.833,0.767 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="143" android:startOffset="107" android:valueFrom="M30.81 32.26 C30.56,32.49 30.27,38.76 29.96,38.9 C29.77,39.46 29.13,39.94 28.57,40.26 C28.15,40.51 26.93,40.65 26.4,40.65 C26.18,40.65 11.91,40.62 11.71,40.58 C10.68,40.53 9.06,39.79 8.89,38.88 C8.6,38.74 8.34,32.48 8.1,32.27 " android:valueTo="M30.64 30.14 C30.64,30.14 30.64,38.14 30.64,38.14 C30.64,38.77 30.36,39.32 29.91,39.69 C29.57,39.97 29.12,40.14 28.64,40.14 C28.64,40.14 10.14,40.14 10.14,40.14 C9.04,40.14 8.14,39.25 8.14,38.14 C8.14,38.14 8.14,30.14 8.14,30.14 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0.331,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="strokeAlpha" android:duration="140" android:startOffset="0" android:valueFrom="1" android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="strokeAlpha" android:duration="50" android:startOffset="140" android:valueFrom="1" android:valueTo="0" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="107" android:startOffset="0" android:valueFrom="M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " android:valueTo="M18.93 32.18 C17.11,32.68 16.62,30.26 16.62,30.26 C16.62,28.78 17.81,27.59 19.39,27.59 C20.96,27.59 22.15,28.78 22.15,30.26 C22.15,30.26 22.15,30.34 22.15,30.34 C22.15,30.89 21.11,32.54 19.57,32.19 C19.19,32.1 20.48,31.09 20.34,30.71 C20.34,30.71 20.02,29.88 20.02,29.88 C19.88,29.5 19.53,29.25 19.15,29.25 C18.63,29.25 18,29.67 18,30.22 C18,30.57 18.06,31.08 18.32,31.51 C18.49,31.8 19.02,32.25 19.79,32.04 C20.41,31.7 20.38,31.36 20.38,31.36 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.833,0.767 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="107" android:startOffset="107" android:valueFrom="M18.93 32.18 C17.11,32.68 16.62,30.26 16.62,30.26 C16.62,28.78 17.81,27.59 19.39,27.59 C20.96,27.59 22.15,28.78 22.15,30.26 C22.15,30.26 22.15,30.34 22.15,30.34 C22.15,30.89 21.11,32.54 19.57,32.19 C19.19,32.1 20.48,31.09 20.34,30.71 C20.34,30.71 20.02,29.88 20.02,29.88 C19.88,29.5 19.53,29.25 19.15,29.25 C18.63,29.25 18,29.67 18,30.22 C18,30.57 18.06,31.08 18.32,31.51 C18.49,31.8 19.02,32.25 19.79,32.04 C20.41,31.7 20.38,31.36 20.38,31.36 " android:valueTo="M19.42 31.53 C18.15,31.52 18.11,30.33 18.11,30.33 C18.11,29.59 18.66,28.98 19.4,28.98 C20.13,28.98 20.69,29.59 20.69,30.33 C20.69,30.33 20.69,30.37 20.69,30.37 C20.69,30.64 20.49,30.87 20.25,30.87 C20.07,30.87 19.91,30.74 19.84,30.55 C19.84,30.55 19.69,30.14 19.69,30.14 C19.63,29.94 19.46,29.82 19.28,29.82 C19.04,29.82 18.61,30.02 18.61,30.29 C18.61,30.43 18.6,30.75 18.76,31.03 C18.87,31.21 19.21,31.77 19.96,31.41 C20.69,31.01 20.69,30.34 20.69,30.34 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="250" android:startOffset="0" android:valueFrom="M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " android:valueTo="M8.14 30.22 C8.14,30.22 8.14,22.22 8.14,22.22 C8.14,21.71 8.33,21.25 8.64,20.9 C9,20.48 9.54,20.22 10.14,20.22 C10.14,20.22 28.64,20.22 28.64,20.22 C29.75,20.22 30.64,21.11 30.64,22.22 C30.64,22.22 30.64,30.14 30.64,30.14 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.189,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="95" android:startOffset="0" android:valueFrom="M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " android:valueTo="M11.47 14.84 C11.47,14.84 12.21,11.43 13.54,9.84 C14.84,8.28 16.68,7.22 19.35,7.22 C22.01,7.22 23.98,8.4 25.19,10.18 C26.39,11.96 27.25,14.84 27.25,14.84 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.833,0.767 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="24" android:startOffset="95" android:valueFrom="M11.47 14.84 C11.47,14.84 12.21,11.43 13.54,9.84 C14.84,8.28 16.68,7.22 19.35,7.22 C22.01,7.22 23.98,8.4 25.19,10.18 C26.39,11.96 27.25,14.84 27.25,14.84 " android:valueTo="M12.11 16.85 C12.11,16.85 12.82,12.71 13.37,11.5 C14.17,9.24 16.38,7.53 19.35,7.53 C22.32,7.53 24.61,9.32 25.35,11.72 C25.61,12.64 26.62,16.85 26.62,16.85 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0.833,0.767 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="81" android:startOffset="119" android:valueFrom="M12.11 16.85 C12.11,16.85 12.82,12.71 13.37,11.5 C14.17,9.24 16.38,7.53 19.35,7.53 C22.32,7.53 24.61,9.32 25.35,11.72 C25.61,12.64 26.62,16.85 26.62,16.85 " android:valueTo="M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0.261,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="233" android:startOffset="200" android:valueFrom="M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " android:valueTo="M37.91 20.05 C37.91,20.05 37.89,14.16 37.89,14.16 C37.89,10.79 35.15,8.05 31.86,8.03 C28.46,8.01 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.123,0 0.23,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="fillAlpha" android:duration="120" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="fillAlpha" android:duration="20" android:startOffset="120" android:valueFrom="0" android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="120" android:startOffset="0" android:valueFrom="1.4186600000000003" android:valueTo="1.4186600000000003" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="120" android:startOffset="0" android:valueFrom="1.4186600000000003" android:valueTo="1.4186600000000003" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="130" android:startOffset="120" android:valueFrom="1.4186600000000003" android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="130" android:startOffset="120" android:valueFrom="1.4186600000000003" android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="517" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/lock_to_unlock.xml b/packages/SystemUI/res/anim/lock_to_unlock.xml
new file mode 100644
index 0000000..ec51c01
--- /dev/null
+++ b/packages/SystemUI/res/anim/lock_to_unlock.xml
@@ -0,0 +1,163 @@
+<?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.
+-->
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android">
+ <aapt:attr name="android:drawable">
+ <vector android:height="65dp" android:width="46dp" android:viewportHeight="65" android:viewportWidth="46">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_2_G_N_10_N_11_T_0" android:translateX="-27.5" android:translateY="-17.5">
+ <group android:name="_R_G_L_2_G_N_10_T_1" android:translateX="50.25" android:translateY="61">
+ <group android:name="_R_G_L_2_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5">
+ <group android:name="_R_G_L_2_G" android:translateX="-0.375" android:translateY="-22.375">
+ <path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="_R_G_L_1_G_N_10_N_11_T_0" android:translateX="-27.5" android:translateY="-17.5">
+ <group android:name="_R_G_L_1_G_N_10_T_1" android:translateX="50.25" android:translateY="61">
+ <group android:name="_R_G_L_1_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5">
+ <group android:name="_R_G_L_1_G" android:translateX="5" android:translateY="-22.5">
+ <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M2.5 15 C2.5,15 2.5,8.61 2.5,8.61 C2.5,5.24 5.3,2.5 8.75,2.5 C12.2,2.5 15,5.24 15,8.61 C15,8.61 15,15 15,15 " />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="_R_G_L_0_G_N_10_N_11_T_0" android:translateX="-27.5" android:translateY="-17.5">
+ <group android:name="_R_G_L_0_G_N_10_T_1" android:translateX="50.25" android:translateY="61">
+ <group android:name="_R_G_L_0_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5">
+ <group android:name="_R_G_L_0_G" android:translateX="11" android:translateY="-0.25" android:pivotX="2.75" android:pivotY="2.75" android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#b7f29f" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_2_G_N_10_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateY" android:duration="133" android:startOffset="0" android:valueFrom="61" android:valueTo="57" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.369,0 0.6,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="translateY" android:duration="133" android:startOffset="133" android:valueFrom="57" android:valueTo="62.125" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.436,0 0.58,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="translateY" android:duration="100" android:startOffset="267" android:valueFrom="62.125" android:valueTo="61" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.449,0 0.469,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="67" android:startOffset="0" android:valueFrom="M2.5 15 C2.5,15 2.5,8.61 2.5,8.61 C2.5,5.24 5.3,2.5 8.75,2.5 C12.2,2.5 15,5.24 15,8.61 C15,8.61 15,15 15,15 " android:valueTo="M2.5 9.94 C2.5,9.94 2.5,3.55 2.5,3.55 C2.5,0.17 5.3,-2.56 8.75,-2.56 C12.2,-2.56 15,0.17 15,3.55 C15,3.55 15,15 15,15 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.552,0 0.453,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData" android:duration="333" android:startOffset="67" android:valueFrom="M2.5 9.94 C2.5,9.94 2.5,3.55 2.5,3.55 C2.5,0.17 5.3,-2.56 8.75,-2.56 C12.2,-2.56 15,0.17 15,3.55 C15,3.55 15,15 15,15 " android:valueTo="M27.19 14.81 C27.19,14.81 27.19,8.3 27.19,8.3 C27.19,4.92 24.44,2.88 21.19,2.75 C17.74,2.62 15,4.74 15,8.11 C15,8.11 15,15 15,15 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.476,0 0.396,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_10_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateY" android:duration="133" android:startOffset="0" android:valueFrom="61" android:valueTo="57" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.369,0 0.6,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="translateY" android:duration="133" android:startOffset="133" android:valueFrom="57" android:valueTo="62.125" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.436,0 0.58,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="translateY" android:duration="100" android:startOffset="267" android:valueFrom="62.125" android:valueTo="61" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.449,0 0.469,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX" android:duration="100" android:startOffset="0" android:valueFrom="1" android:valueTo="0.8200000000000001" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.415,0 0.338,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="100" android:startOffset="0" android:valueFrom="1" android:valueTo="0.8200000000000001" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.415,0 0.338,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleX" android:duration="283" android:startOffset="100" android:valueFrom="0.8200000000000001" android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.249,0 0.529,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="283" android:startOffset="100" android:valueFrom="0.8200000000000001" android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.249,0 0.529,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_10_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateY" android:duration="133" android:startOffset="0" android:valueFrom="61" android:valueTo="57" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.369,0 0.6,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="translateY" android:duration="133" android:startOffset="133" android:valueFrom="57" android:valueTo="62.125" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.436,0 0.58,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="translateY" android:duration="100" android:startOffset="267" android:valueFrom="62.125" android:valueTo="61" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.449,0 0.469,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="517" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml
index 99e8116..3c9e44e 100644
--- a/packages/SystemUI/res/layout/auth_biometric_contents.xml
+++ b/packages/SystemUI/res/layout/auth_biometric_contents.xml
@@ -52,6 +52,7 @@
android:layout_width="@dimen/biometric_dialog_biometric_icon_size"
android:layout_height="@dimen/biometric_dialog_biometric_icon_size"
android:layout_gravity="center"
+ android:contentDescription="@null"
android:scaleType="fitXY" />
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/people_space_activity_no_conversations.xml b/packages/SystemUI/res/layout/people_space_activity_no_conversations.xml
index e87bf61..2e9ff07 100644
--- a/packages/SystemUI/res/layout/people_space_activity_no_conversations.xml
+++ b/packages/SystemUI/res/layout/people_space_activity_no_conversations.xml
@@ -15,6 +15,7 @@
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/top_level"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -55,7 +56,7 @@
android:background="@drawable/rounded_bg_full_large_radius"
android:onClick="dismissActivity"
android:text="@string/got_it"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?androidprv:attr/textColorOnAccent"
android:layout_marginBottom="60dp"
android:layout_alignParentBottom="true" />
diff --git a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
index 892f64b..4043656 100644
--- a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
+++ b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
@@ -131,6 +131,7 @@
<TextView
android:id="@+id/messages_count"
android:gravity="end"
+ android:layout_marginStart="-32dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
@@ -147,6 +148,7 @@
android:id="@+id/predefined_icon"
android:tint="?android:attr/textColorSecondary"
android:gravity="end|center_vertical"
+ android:layout_marginStart="-24dp"
android:layout_width="@dimen/regular_predefined_icon"
android:layout_height="@dimen/regular_predefined_icon" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_customize_panel_content.xml b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
index 8ca1b8e..3be9993 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel_content.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
@@ -19,7 +19,7 @@
<View
android:id="@+id/customizer_transparent_view"
android:layout_width="match_parent"
- android:layout_height="@*android:dimen/quick_qs_offset_height"
+ android:layout_height="@dimen/qs_header_system_icons_area_height"
android:background="@android:color/transparent" />
<com.android.keyguard.AlphaOptimizedLinearLayout
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 5b9ca1b..74c39a3 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -21,7 +21,7 @@
android:layout_height="@*android:dimen/quick_qs_offset_height"
android:clipChildren="false"
android:clipToPadding="false"
- android:minHeight="48dp"
+ android:minHeight="@dimen/qs_header_row_min_height"
android:clickable="false"
android:focusable="true"
android:theme="@style/Theme.SystemUI.QuickSettings.Header">
@@ -31,7 +31,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="48dp"
- android:minHeight="48dp"
+ android:minHeight="@dimen/qs_header_row_min_height"
android:gravity="center_vertical|start"
android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
@@ -43,7 +43,7 @@
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
- android:minHeight="48dp"
+ android:minHeight="@dimen/qs_header_row_min_height"
android:minWidth="48dp"
android:layout_marginStart="8dp"
android:layout_gravity="end|center_vertical"
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index f9dcd39..1be20d8 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -42,21 +42,21 @@
android:layout_gravity="top"
android:clipChildren="false"
android:clipToPadding="false">
- <!-- Time, icons and Carrier (only in QS) -->
- <include layout="@layout/quick_qs_status_icons"/>
+ <!-- Time, icons and Carrier (only in QS) -->
+ <include layout="@layout/quick_qs_status_icons"/>
- <com.android.systemui.qs.QuickQSPanel
- android:id="@+id/quick_qs_panel"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/quick_qs_status_icons"
- android:layout_marginTop="@dimen/qqs_layout_margin_top"
- android:accessibilityTraversalAfter="@id/quick_qs_status_icons"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:focusable="true"
- android:paddingBottom="10dp"
- android:importantForAccessibility="yes" />
+ <com.android.systemui.qs.QuickQSPanel
+ android:id="@+id/quick_qs_panel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/quick_qs_status_icons"
+ android:layout_marginTop="@dimen/qqs_layout_margin_top"
+ android:accessibilityTraversalAfter="@id/quick_qs_status_icons"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:focusable="true"
+ android:paddingBottom="10dp"
+ android:importantForAccessibility="yes" />
</RelativeLayout>
</com.android.systemui.qs.QuickStatusBarHeader>
diff --git a/packages/SystemUI/res/layout/rotate_suggestion.xml b/packages/SystemUI/res/layout/rotate_suggestion.xml
index 194d2e0..1c3eedb 100644
--- a/packages/SystemUI/res/layout/rotate_suggestion.xml
+++ b/packages/SystemUI/res/layout/rotate_suggestion.xml
@@ -14,16 +14,19 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-
-<com.android.systemui.navigationbar.buttons.KeyButtonView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/rotate_suggestion"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_weight="0"
- android:scaleType="center"
- android:visibility="invisible"
- android:contentDescription="@string/accessibility_rotate_button"
- android:paddingStart="@dimen/navigation_key_padding"
- android:paddingEnd="@dimen/navigation_key_padding"
-/>
\ No newline at end of file
+ >
+
+ <com.android.systemui.navigationbar.buttons.KeyButtonView
+ android:id="@+id/rotate_suggestion"
+ android:layout_width="@dimen/floating_rotation_button_diameter"
+ android:layout_height="@dimen/floating_rotation_button_diameter"
+ android:contentDescription="@string/accessibility_rotate_button"
+ android:paddingStart="@dimen/navigation_key_padding"
+ android:paddingEnd="@dimen/navigation_key_padding"
+ android:layout_gravity="bottom|left"
+ android:scaleType="center"
+ android:visibility="invisible" />
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/split_shade_header.xml b/packages/SystemUI/res/layout/split_shade_header.xml
new file mode 100644
index 0000000..401dc19
--- /dev/null
+++ b/packages/SystemUI/res/layout/split_shade_header.xml
@@ -0,0 +1,89 @@
+<?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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/split_shade_status_bar"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/split_shade_header_height"
+ android:minHeight="@dimen/split_shade_header_min_height"
+ android:clickable="false"
+ android:focusable="true"
+ android:paddingLeft="@dimen/qs_panel_padding"
+ android:paddingRight="@dimen/qs_panel_padding"
+ android:visibility="gone"
+ android:theme="@style/Theme.SystemUI.QuickSettings.Header">
+
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/clock"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:minWidth="48dp"
+ android:minHeight="@dimen/split_shade_header_min_height"
+ android:gravity="start|center_vertical"
+ android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
+ android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.QS.Status" />
+
+ <com.android.systemui.statusbar.policy.DateView
+ android:id="@+id/date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start|center_vertical"
+ android:gravity="center_vertical"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.QS.Status"
+ systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" />
+
+ <FrameLayout
+ android:id="@+id/rightLayout"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="end">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="end|center_vertical">
+
+ <include
+ android:id="@+id/carrier_group"
+ layout="@layout/qs_carrier_group"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="end|center_vertical"
+ android:layout_marginStart="8dp"
+ android:focusable="false"
+ android:minHeight="@dimen/split_shade_header_min_height"
+ android:minWidth="48dp" />
+
+ <com.android.systemui.statusbar.phone.StatusIconContainer
+ android:id="@+id/statusIcons"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingEnd="@dimen/signal_cluster_battery_padding" />
+
+ <com.android.systemui.BatteryMeterView
+ android:id="@+id/batteryRemainingIcon"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ systemui:textAppearance="@style/TextAppearance.QS.Status" />
+ </LinearLayout>
+ </FrameLayout>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index dbbf641..cf91a2b 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -52,9 +52,12 @@
<include layout="@layout/dock_info_bottom_area_overlay" />
<com.android.keyguard.LockIconView
+ android:id="@+id/lock_icon_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:id="@+id/lock_icon_view" />
+ android:padding="48px"
+ android:layout_gravity="center"
+ android:scaleType="centerCrop"/>
<com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
android:layout_width="match_parent"
@@ -64,6 +67,8 @@
android:clipToPadding="false"
android:clipChildren="false">
+ <include layout="@layout/split_shade_header"/>
+
<include
layout="@layout/keyguard_status_view"
android:visibility="gone"/>
diff --git a/packages/SystemUI/res/layout/udfps_keyguard_view.xml b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
index 33baa4e..8834ac0 100644
--- a/packages/SystemUI/res/layout/udfps_keyguard_view.xml
+++ b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
@@ -30,16 +30,15 @@
android:visibility="gone"/>
<!-- Fingerprint -->
-
<!-- AOD dashed fingerprint icon with moving dashes -->
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/udfps_aod_fp"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:padding="48px"
android:layout_gravity="center"
android:scaleType="centerCrop"
app:lottie_autoPlay="false"
- android:padding="16dp"
app:lottie_loop="true"
app:lottie_rawRes="@raw/udfps_aod_fp"/>
@@ -48,10 +47,10 @@
android:id="@+id/udfps_lockscreen_fp"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:padding="48px"
android:layout_gravity="center"
android:scaleType="centerCrop"
app:lottie_autoPlay="false"
app:lottie_loop="false"
- android:padding="16dp"
app:lottie_rawRes="@raw/udfps_lockscreen_fp"/>
</com.android.systemui.biometrics.UdfpsKeyguardView>
diff --git a/packages/SystemUI/res/raw/udfps_aod_fp.json b/packages/SystemUI/res/raw/udfps_aod_fp.json
index cdac332..3247fe7 100644
--- a/packages/SystemUI/res/raw/udfps_aod_fp.json
+++ b/packages/SystemUI/res/raw/udfps_aod_fp.json
@@ -1,95 +1,1424 @@
{
- "v": "5.7.8",
- "fr": 60,
- "ip": 0,
- "op": 361,
- "w": 180,
- "h": 185,
- "nm": "fingerprint_burn_in_Loop",
- "ddd": 0,
- "assets": [],
- "layers": [
+ "v":"5.7.8",
+ "fr":60,
+ "ip":0,
+ "op":361,
+ "w":46,
+ "h":65,
+ "nm":"fingerprint_burn_in_Loop_02",
+ "ddd":0,
+ "assets":[
+
+ ],
+ "layers":[
{
- "ddd": 0,
- "ind": 1,
- "ty": 4,
- "nm": "Layer 1 Outlines 10",
- "sr": 1,
- "ks": {
- "o": {
- "a": 0,
- "k": 100,
- "ix": 11
+ "ddd":0,
+ "ind":2,
+ "ty":4,
+ "nm":"Fingerprint_20210701 Outlines 9",
+ "sr":1,
+ "ks":{
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":11
},
- "r": {
- "a": 0,
- "k": 0,
- "ix": 10
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":10
},
- "p": {
- "a": 0,
- "k": [
- 91.456,
- 92.206,
+ "p":{
+ "a":0,
+ "k":[
+ 23.091,
+ 32.5,
0
],
- "ix": 2,
- "l": 2
+ "ix":2,
+ "l":2
},
- "a": {
- "a": 0,
- "k": [
- 20,
- 25,
+ "a":{
+ "a":0,
+ "k":[
+ 19.341,
+ 24.25,
0
],
- "ix": 1,
- "l": 2
+ "ix":1,
+ "l":2
},
- "s": {
- "a": 0,
- "k": [
- 350,
- 350,
+ "s":{
+ "a":0,
+ "k":[
+ 100,
+ 100,
100
],
- "ix": 6,
- "l": 2
+ "ix":6,
+ "l":2
}
},
- "ao": 0,
- "shapes": [
+ "ao":0,
+ "shapes":[
{
- "ty": "gr",
- "it": [
+ "ty":"gr",
+ "it":[
{
- "ind": 0,
- "ty": "sh",
- "ix": 1,
- "ks": {
- "a": 0,
- "k": {
- "i": [
+ "ind":0,
+ "ty":"sh",
+ "ix":1,
+ "ks":{
+ "a":0,
+ "k":{
+ "i":[
[
0,
0
],
[
- -3.684,
+ -1.701,
+ 0.42
+ ],
+ [
+ -1.757,
0
],
[
- -2.883,
- -1.583
- ]
- ],
- "o": [
- [
- 2.883,
- -1.583
+ -1.577,
+ -0.381
],
[
- 3.683,
+ -1.485,
+ -0.816
+ ]
+ ],
+ "o":[
+ [
+ 1.455,
+ -0.799
+ ],
+ [
+ 1.608,
+ -0.397
+ ],
+ [
+ 1.719,
+ 0
+ ],
+ [
+ 1.739,
+ 0.42
+ ],
+ [
+ 0,
+ 0
+ ]
+ ],
+ "v":[
+ [
+ -9.818,
+ 1.227
+ ],
+ [
+ -5.064,
+ -0.618
+ ],
+ [
+ 0,
+ -1.227
+ ],
+ [
+ 4.96,
+ -0.643
+ ],
+ [
+ 9.818,
+ 1.227
+ ]
+ ],
+ "c":false
+ },
+ "ix":2
+ },
+ "nm":"Path 1",
+ "mn":"ADBE Vector Shape - Group",
+ "hd":false
+ },
+ {
+ "ty":"st",
+ "c":{
+ "a":0,
+ "k":[
+ 1,
+ 1,
+ 1,
+ 1
+ ],
+ "ix":3
+ },
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":4
+ },
+ "w":{
+ "a":0,
+ "k":1,
+ "ix":5
+ },
+ "lc":2,
+ "lj":1,
+ "ml":10,
+ "bm":0,
+ "nm":"Stroke 1",
+ "mn":"ADBE Vector Graphic - Stroke",
+ "hd":false
+ },
+ {
+ "ty":"tr",
+ "p":{
+ "a":0,
+ "k":[
+ 19.341,
+ 7.477
+ ],
+ "ix":2
+ },
+ "a":{
+ "a":0,
+ "k":[
+ 0,
+ 0
+ ],
+ "ix":1
+ },
+ "s":{
+ "a":0,
+ "k":[
+ 100,
+ 100
+ ],
+ "ix":3
+ },
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":6
+ },
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":7
+ },
+ "sk":{
+ "a":0,
+ "k":0,
+ "ix":4
+ },
+ "sa":{
+ "a":0,
+ "k":0,
+ "ix":5
+ },
+ "nm":"Transform"
+ }
+ ],
+ "nm":"Top",
+ "np":2,
+ "cix":2,
+ "bm":0,
+ "ix":1,
+ "mn":"ADBE Vector Group",
+ "hd":false
+ },
+ {
+ "ty":"tm",
+ "s":{
+ "a":0,
+ "k":0,
+ "ix":1
+ },
+ "e":{
+ "a":0,
+ "k":17,
+ "ix":2
+ },
+ "o":{
+ "a":1,
+ "k":[
+ {
+ "i":{
+ "x":[
+ 0.833
+ ],
+ "y":[
+ 0.833
+ ]
+ },
+ "o":{
+ "x":[
+ 0.167
+ ],
+ "y":[
+ 0.167
+ ]
+ },
+ "t":0,
+ "s":[
+ 246
+ ]
+ },
+ {
+ "t":360,
+ "s":[
+ 1326
+ ]
+ }
+ ],
+ "ix":3
+ },
+ "m":1,
+ "ix":2,
+ "nm":"Trim Paths 1",
+ "mn":"ADBE Vector Filter - Trim",
+ "hd":false
+ },
+ {
+ "ty":"gr",
+ "it":[
+ {
+ "ty":"tm",
+ "s":{
+ "a":0,
+ "k":0,
+ "ix":1
+ },
+ "e":{
+ "a":0,
+ "k":17,
+ "ix":2
+ },
+ "o":{
+ "a":0,
+ "k":0,
+ "ix":3
+ },
+ "m":1,
+ "ix":1,
+ "nm":"Trim Paths 1",
+ "mn":"ADBE Vector Filter - Trim",
+ "hd":false
+ },
+ {
+ "ty":"tr",
+ "p":{
+ "a":0,
+ "k":[
+ 0,
+ 0
+ ],
+ "ix":2
+ },
+ "a":{
+ "a":0,
+ "k":[
+ 0,
+ 0
+ ],
+ "ix":1
+ },
+ "s":{
+ "a":0,
+ "k":[
+ 100,
+ 100
+ ],
+ "ix":3
+ },
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":6
+ },
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":7
+ },
+ "sk":{
+ "a":0,
+ "k":0,
+ "ix":4
+ },
+ "sa":{
+ "a":0,
+ "k":0,
+ "ix":5
+ },
+ "nm":"Transform"
+ }
+ ],
+ "nm":"Group 1",
+ "np":1,
+ "cix":2,
+ "bm":0,
+ "ix":3,
+ "mn":"ADBE Vector Group",
+ "hd":false
+ }
+ ],
+ "ip":0,
+ "op":600,
+ "st":0,
+ "bm":0
+ },
+ {
+ "ddd":0,
+ "ind":3,
+ "ty":4,
+ "nm":"Fingerprint_20210701 Outlines 8",
+ "sr":1,
+ "ks":{
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":11
+ },
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":10
+ },
+ "p":{
+ "a":0,
+ "k":[
+ 23.091,
+ 32.5,
+ 0
+ ],
+ "ix":2,
+ "l":2
+ },
+ "a":{
+ "a":0,
+ "k":[
+ 19.341,
+ 24.25,
+ 0
+ ],
+ "ix":1,
+ "l":2
+ },
+ "s":{
+ "a":0,
+ "k":[
+ 100,
+ 100,
+ 100
+ ],
+ "ix":6,
+ "l":2
+ }
+ },
+ "ao":0,
+ "shapes":[
+ {
+ "ty":"gr",
+ "it":[
+ {
+ "ind":0,
+ "ty":"sh",
+ "ix":1,
+ "ks":{
+ "a":0,
+ "k":{
+ "i":[
+ [
+ 0,
+ 0
+ ],
+ [
+ -1.701,
+ 0.42
+ ],
+ [
+ -1.757,
+ 0
+ ],
+ [
+ -1.577,
+ -0.381
+ ],
+ [
+ -1.485,
+ -0.816
+ ]
+ ],
+ "o":[
+ [
+ 1.455,
+ -0.799
+ ],
+ [
+ 1.608,
+ -0.397
+ ],
+ [
+ 1.719,
+ 0
+ ],
+ [
+ 1.739,
+ 0.42
+ ],
+ [
+ 0,
+ 0
+ ]
+ ],
+ "v":[
+ [
+ -9.818,
+ 1.227
+ ],
+ [
+ -5.064,
+ -0.618
+ ],
+ [
+ 0,
+ -1.227
+ ],
+ [
+ 4.96,
+ -0.643
+ ],
+ [
+ 9.818,
+ 1.227
+ ]
+ ],
+ "c":false
+ },
+ "ix":2
+ },
+ "nm":"Path 1",
+ "mn":"ADBE Vector Shape - Group",
+ "hd":false
+ },
+ {
+ "ty":"st",
+ "c":{
+ "a":0,
+ "k":[
+ 1,
+ 1,
+ 1,
+ 1
+ ],
+ "ix":3
+ },
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":4
+ },
+ "w":{
+ "a":0,
+ "k":1,
+ "ix":5
+ },
+ "lc":2,
+ "lj":1,
+ "ml":10,
+ "bm":0,
+ "nm":"Stroke 1",
+ "mn":"ADBE Vector Graphic - Stroke",
+ "hd":false
+ },
+ {
+ "ty":"tr",
+ "p":{
+ "a":0,
+ "k":[
+ 19.341,
+ 7.477
+ ],
+ "ix":2
+ },
+ "a":{
+ "a":0,
+ "k":[
+ 0,
+ 0
+ ],
+ "ix":1
+ },
+ "s":{
+ "a":0,
+ "k":[
+ 100,
+ 100
+ ],
+ "ix":3
+ },
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":6
+ },
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":7
+ },
+ "sk":{
+ "a":0,
+ "k":0,
+ "ix":4
+ },
+ "sa":{
+ "a":0,
+ "k":0,
+ "ix":5
+ },
+ "nm":"Transform"
+ }
+ ],
+ "nm":"Top",
+ "np":2,
+ "cix":2,
+ "bm":0,
+ "ix":1,
+ "mn":"ADBE Vector Group",
+ "hd":false
+ },
+ {
+ "ty":"tm",
+ "s":{
+ "a":0,
+ "k":0,
+ "ix":1
+ },
+ "e":{
+ "a":0,
+ "k":54,
+ "ix":2
+ },
+ "o":{
+ "a":1,
+ "k":[
+ {
+ "i":{
+ "x":[
+ 0.833
+ ],
+ "y":[
+ 0.833
+ ]
+ },
+ "o":{
+ "x":[
+ 0.167
+ ],
+ "y":[
+ 0.167
+ ]
+ },
+ "t":0,
+ "s":[
+ 0
+ ]
+ },
+ {
+ "t":360,
+ "s":[
+ 1080
+ ]
+ }
+ ],
+ "ix":3
+ },
+ "m":1,
+ "ix":2,
+ "nm":"Trim Paths 1",
+ "mn":"ADBE Vector Filter - Trim",
+ "hd":false
+ }
+ ],
+ "ip":0,
+ "op":600,
+ "st":0,
+ "bm":0
+ },
+ {
+ "ddd":0,
+ "ind":4,
+ "ty":4,
+ "nm":"Fingerprint_20210701 Outlines 7",
+ "sr":1,
+ "ks":{
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":11
+ },
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":10
+ },
+ "p":{
+ "a":0,
+ "k":[
+ 23.091,
+ 32.5,
+ 0
+ ],
+ "ix":2,
+ "l":2
+ },
+ "a":{
+ "a":0,
+ "k":[
+ 19.341,
+ 24.25,
+ 0
+ ],
+ "ix":1,
+ "l":2
+ },
+ "s":{
+ "a":0,
+ "k":[
+ 100,
+ 100,
+ 100
+ ],
+ "ix":6,
+ "l":2
+ }
+ },
+ "ao":0,
+ "shapes":[
+ {
+ "ty":"gr",
+ "it":[
+ {
+ "ind":0,
+ "ty":"sh",
+ "ix":1,
+ "ks":{
+ "a":0,
+ "k":{
+ "i":[
+ [
+ 0,
+ 0
+ ],
+ [
+ -2.446,
+ 1.161
+ ],
+ [
+ -1.168,
+ 0.275
+ ],
+ [
+ -1.439,
+ 0
+ ],
+ [
+ -1.301,
+ -0.304
+ ],
+ [
+ -1.225,
+ -0.66
+ ],
+ [
+ -1.11,
+ -1.844
+ ]
+ ],
+ "o":[
+ [
+ 1.23,
+ -2.044
+ ],
+ [
+ 1.024,
+ -0.486
+ ],
+ [
+ 1.312,
+ -0.31
+ ],
+ [
+ 1.425,
+ 0
+ ],
+ [
+ 1.454,
+ 0.34
+ ],
+ [
+ 2.122,
+ 1.143
+ ],
+ [
+ 0,
+ 0
+ ]
+ ],
+ "v":[
+ [
+ -13.091,
+ 3.273
+ ],
+ [
+ -7.438,
+ -1.646
+ ],
+ [
+ -4.14,
+ -2.797
+ ],
+ [
+ 0,
+ -3.273
+ ],
+ [
+ 4.104,
+ -2.805
+ ],
+ [
+ 8.141,
+ -1.29
+ ],
+ [
+ 13.091,
+ 3.273
+ ]
+ ],
+ "c":false
+ },
+ "ix":2
+ },
+ "nm":"Path 1",
+ "mn":"ADBE Vector Shape - Group",
+ "hd":false
+ },
+ {
+ "ty":"st",
+ "c":{
+ "a":0,
+ "k":[
+ 1,
+ 1,
+ 1,
+ 1
+ ],
+ "ix":3
+ },
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":4
+ },
+ "w":{
+ "a":0,
+ "k":1,
+ "ix":5
+ },
+ "lc":2,
+ "lj":1,
+ "ml":10,
+ "bm":0,
+ "nm":"Stroke 1",
+ "mn":"ADBE Vector Graphic - Stroke",
+ "hd":false
+ },
+ {
+ "ty":"tr",
+ "p":{
+ "a":0,
+ "k":[
+ 19.341,
+ 16.069
+ ],
+ "ix":2
+ },
+ "a":{
+ "a":0,
+ "k":[
+ 0,
+ 0
+ ],
+ "ix":1
+ },
+ "s":{
+ "a":0,
+ "k":[
+ 100,
+ 100
+ ],
+ "ix":3
+ },
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":6
+ },
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":7
+ },
+ "sk":{
+ "a":0,
+ "k":0,
+ "ix":4
+ },
+ "sa":{
+ "a":0,
+ "k":0,
+ "ix":5
+ },
+ "nm":"Transform"
+ }
+ ],
+ "nm":"Mid Top",
+ "np":2,
+ "cix":2,
+ "bm":0,
+ "ix":1,
+ "mn":"ADBE Vector Group",
+ "hd":false
+ },
+ {
+ "ty":"tm",
+ "s":{
+ "a":0,
+ "k":0,
+ "ix":1
+ },
+ "e":{
+ "a":0,
+ "k":38.2,
+ "ix":2
+ },
+ "o":{
+ "a":1,
+ "k":[
+ {
+ "i":{
+ "x":[
+ 0.833
+ ],
+ "y":[
+ 0.833
+ ]
+ },
+ "o":{
+ "x":[
+ 0.167
+ ],
+ "y":[
+ 0.167
+ ]
+ },
+ "t":0,
+ "s":[
+ 170
+ ]
+ },
+ {
+ "t":360,
+ "s":[
+ 890
+ ]
+ }
+ ],
+ "ix":3
+ },
+ "m":1,
+ "ix":2,
+ "nm":"Trim Paths 1",
+ "mn":"ADBE Vector Filter - Trim",
+ "hd":false
+ }
+ ],
+ "ip":0,
+ "op":600,
+ "st":0,
+ "bm":0
+ },
+ {
+ "ddd":0,
+ "ind":5,
+ "ty":4,
+ "nm":"Fingerprint_20210701 Outlines 6",
+ "sr":1,
+ "ks":{
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":11
+ },
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":10
+ },
+ "p":{
+ "a":0,
+ "k":[
+ 23.091,
+ 32.5,
+ 0
+ ],
+ "ix":2,
+ "l":2
+ },
+ "a":{
+ "a":0,
+ "k":[
+ 19.341,
+ 24.25,
+ 0
+ ],
+ "ix":1,
+ "l":2
+ },
+ "s":{
+ "a":0,
+ "k":[
+ 100,
+ 100,
+ 100
+ ],
+ "ix":6,
+ "l":2
+ }
+ },
+ "ao":0,
+ "shapes":[
+ {
+ "ty":"gr",
+ "it":[
+ {
+ "ind":0,
+ "ty":"sh",
+ "ix":1,
+ "ks":{
+ "a":0,
+ "k":{
+ "i":[
+ [
+ 0,
+ 0
+ ],
+ [
+ -2.446,
+ 1.161
+ ],
+ [
+ -1.168,
+ 0.275
+ ],
+ [
+ -1.439,
+ 0
+ ],
+ [
+ -1.301,
+ -0.304
+ ],
+ [
+ -1.225,
+ -0.66
+ ],
+ [
+ -1.11,
+ -1.844
+ ]
+ ],
+ "o":[
+ [
+ 1.23,
+ -2.044
+ ],
+ [
+ 1.024,
+ -0.486
+ ],
+ [
+ 1.312,
+ -0.31
+ ],
+ [
+ 1.425,
+ 0
+ ],
+ [
+ 1.454,
+ 0.34
+ ],
+ [
+ 2.122,
+ 1.143
+ ],
+ [
+ 0,
+ 0
+ ]
+ ],
+ "v":[
+ [
+ -13.091,
+ 3.273
+ ],
+ [
+ -7.438,
+ -1.646
+ ],
+ [
+ -4.14,
+ -2.797
+ ],
+ [
+ 0,
+ -3.273
+ ],
+ [
+ 4.104,
+ -2.805
+ ],
+ [
+ 8.141,
+ -1.29
+ ],
+ [
+ 13.091,
+ 3.273
+ ]
+ ],
+ "c":false
+ },
+ "ix":2
+ },
+ "nm":"Path 1",
+ "mn":"ADBE Vector Shape - Group",
+ "hd":false
+ },
+ {
+ "ty":"st",
+ "c":{
+ "a":0,
+ "k":[
+ 1,
+ 1,
+ 1,
+ 1
+ ],
+ "ix":3
+ },
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":4
+ },
+ "w":{
+ "a":0,
+ "k":1,
+ "ix":5
+ },
+ "lc":2,
+ "lj":1,
+ "ml":10,
+ "bm":0,
+ "nm":"Stroke 1",
+ "mn":"ADBE Vector Graphic - Stroke",
+ "hd":false
+ },
+ {
+ "ty":"tr",
+ "p":{
+ "a":0,
+ "k":[
+ 19.341,
+ 16.069
+ ],
+ "ix":2
+ },
+ "a":{
+ "a":0,
+ "k":[
+ 0,
+ 0
+ ],
+ "ix":1
+ },
+ "s":{
+ "a":0,
+ "k":[
+ 100,
+ 100
+ ],
+ "ix":3
+ },
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":6
+ },
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":7
+ },
+ "sk":{
+ "a":0,
+ "k":0,
+ "ix":4
+ },
+ "sa":{
+ "a":0,
+ "k":0,
+ "ix":5
+ },
+ "nm":"Transform"
+ }
+ ],
+ "nm":"Mid Top",
+ "np":2,
+ "cix":2,
+ "bm":0,
+ "ix":1,
+ "mn":"ADBE Vector Group",
+ "hd":false
+ },
+ {
+ "ty":"tm",
+ "s":{
+ "a":0,
+ "k":0,
+ "ix":1
+ },
+ "e":{
+ "a":0,
+ "k":34.2,
+ "ix":2
+ },
+ "o":{
+ "a":1,
+ "k":[
+ {
+ "i":{
+ "x":[
+ 0.833
+ ],
+ "y":[
+ 0.833
+ ]
+ },
+ "o":{
+ "x":[
+ 0.167
+ ],
+ "y":[
+ 0.167
+ ]
+ },
+ "t":0,
+ "s":[
+ 0
+ ]
+ },
+ {
+ "t":360,
+ "s":[
+ 720
+ ]
+ }
+ ],
+ "ix":3
+ },
+ "m":1,
+ "ix":2,
+ "nm":"Trim Paths 1",
+ "mn":"ADBE Vector Filter - Trim",
+ "hd":false
+ }
+ ],
+ "ip":0,
+ "op":600,
+ "st":0,
+ "bm":0
+ },
+ {
+ "ddd":0,
+ "ind":6,
+ "ty":4,
+ "nm":"Fingerprint_20210701 Outlines 5",
+ "sr":1,
+ "ks":{
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":11
+ },
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":10
+ },
+ "p":{
+ "a":0,
+ "k":[
+ 23.091,
+ 32.5,
+ 0
+ ],
+ "ix":2,
+ "l":2
+ },
+ "a":{
+ "a":0,
+ "k":[
+ 19.341,
+ 24.25,
+ 0
+ ],
+ "ix":1,
+ "l":2
+ },
+ "s":{
+ "a":0,
+ "k":[
+ 100,
+ 100,
+ 100
+ ],
+ "ix":6,
+ "l":2
+ }
+ },
+ "ao":0,
+ "shapes":[
+ {
+ "ty":"gr",
+ "it":[
+ {
+ "ind":0,
+ "ty":"sh",
+ "ix":1,
+ "ks":{
+ "a":0,
+ "k":{
+ "i":[
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0
+ ],
+ [
+ -6.53,
+ 0
+ ],
+ [
+ 0,
+ -5.793
+ ],
+ [
+ 0,
+ 0
+ ],
+ [
+ 2.159,
+ 0
+ ],
+ [
+ 0.59,
+ 1.489
+ ],
+ [
+ 0,
+ 0
+ ],
+ [
+ 1.587,
+ 0
+ ],
+ [
+ 0,
+ -2.16
+ ],
+ [
+ -0.81,
+ -1.363
+ ],
+ [
+ -0.844,
+ -0.674
+ ],
+ [
+ 0,
+ 0
+ ]
+ ],
+ "o":[
+ [
+ -0.753,
+ -2.095
+ ],
+ [
+ 0,
+ -5.793
+ ],
+ [
+ 6.529,
+ 0
+ ],
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 2.16
+ ],
+ [
+ -1.604,
+ 0
+ ],
+ [
+ 0,
+ 0
+ ],
+ [
+ -0.589,
+ -1.489
+ ],
+ [
+ -2.161,
+ 0
+ ],
+ [
+ 0,
+ 1.62
+ ],
+ [
+ 0.54,
+ 0.909
+ ],
+ [
+ 0,
0
],
[
@@ -97,254 +1426,374 @@
0
]
],
- "v": [
+ "v":[
[
- -10.417,
- 1.25
+ -10.702,
+ 5.728
+ ],
+ [
+ -11.454,
+ 1.506
],
[
0.001,
- -1.25
+ -9
],
[
- 10.417,
- 1.25
+ 11.454,
+ 1.506
+ ],
+ [
+ 11.454,
+ 1.817
+ ],
+ [
+ 7.544,
+ 5.728
+ ],
+ [
+ 3.926,
+ 3.273
+ ],
+ [
+ 2.618,
+ 0
+ ],
+ [
+ -0.997,
+ -2.454
+ ],
+ [
+ -4.91,
+ 1.457
+ ],
+ [
+ -3.657,
+ 6.014
+ ],
+ [
+ -1.57,
+ 8.412
+ ],
+ [
+ -0.818,
+ 9
]
],
- "c": false
+ "c":false
},
- "ix": 2
+ "ix":2
},
- "nm": "Path 1",
- "mn": "ADBE Vector Shape - Group",
- "hd": false
+ "nm":"Path 1",
+ "mn":"ADBE Vector Shape - Group",
+ "hd":false
},
{
- "ty": "tm",
- "s": {
- "a": 0,
- "k": 0,
- "ix": 1
- },
- "e": {
- "a": 0,
- "k": 17,
- "ix": 2
- },
- "o": {
- "a": 1,
- "k": [
- {
- "i": {
- "x": [
- 0.833
- ],
- "y": [
- 0.833
- ]
- },
- "o": {
- "x": [
- 0.167
- ],
- "y": [
- 0.167
- ]
- },
- "t": 0,
- "s": [
- 246
- ]
- },
- {
- "t": 360,
- "s": [
- 1326
- ]
- }
- ],
- "ix": 3
- },
- "m": 1,
- "ix": 2,
- "nm": "Trim Paths 1",
- "mn": "ADBE Vector Filter - Trim",
- "hd": false
- },
- {
- "ty": "st",
- "c": {
- "a": 0,
- "k": [
+ "ty":"st",
+ "c":{
+ "a":0,
+ "k":[
1,
1,
1,
1
],
- "ix": 3
+ "ix":3
},
- "o": {
- "a": 0,
- "k": 100,
- "ix": 4
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":4
},
- "w": {
- "a": 0,
- "k": 1,
- "ix": 5
+ "w":{
+ "a":0,
+ "k":1,
+ "ix":5
},
- "lc": 2,
- "lj": 1,
- "ml": 10,
- "bm": 0,
- "nm": "Stroke 1",
- "mn": "ADBE Vector Graphic - Stroke",
- "hd": false
+ "lc":2,
+ "lj":1,
+ "ml":10,
+ "bm":0,
+ "nm":"Stroke 1",
+ "mn":"ADBE Vector Graphic - Stroke",
+ "hd":false
},
{
- "ty": "tr",
- "p": {
- "a": 0,
- "k": [
- 19.999,
- 7.5
+ "ty":"tr",
+ "p":{
+ "a":0,
+ "k":[
+ 19.341,
+ 28.341
],
- "ix": 2
+ "ix":2
},
- "a": {
- "a": 0,
- "k": [
+ "a":{
+ "a":0,
+ "k":[
0,
0
],
- "ix": 1
+ "ix":1
},
- "s": {
- "a": 0,
- "k": [
+ "s":{
+ "a":0,
+ "k":[
100,
100
],
- "ix": 3
+ "ix":3
},
- "r": {
- "a": 0,
- "k": 0,
- "ix": 6
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":6
},
- "o": {
- "a": 0,
- "k": 100,
- "ix": 7
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":7
},
- "sk": {
- "a": 0,
- "k": 0,
- "ix": 4
+ "sk":{
+ "a":0,
+ "k":0,
+ "ix":4
},
- "sa": {
- "a": 0,
- "k": 0,
- "ix": 5
+ "sa":{
+ "a":0,
+ "k":0,
+ "ix":5
},
- "nm": "Transform"
+ "nm":"Transform"
}
],
- "nm": "Group 3",
- "np": 3,
- "cix": 2,
- "bm": 0,
- "ix": 1,
- "mn": "ADBE Vector Group",
- "hd": false
+ "nm":"Inside to dot ",
+ "np":2,
+ "cix":2,
+ "bm":0,
+ "ix":1,
+ "mn":"ADBE Vector Group",
+ "hd":false
+ },
+ {
+ "ty":"tm",
+ "s":{
+ "a":0,
+ "k":0,
+ "ix":1
+ },
+ "e":{
+ "a":0,
+ "k":35,
+ "ix":2
+ },
+ "o":{
+ "a":1,
+ "k":[
+ {
+ "i":{
+ "x":[
+ 0.833
+ ],
+ "y":[
+ 0.833
+ ]
+ },
+ "o":{
+ "x":[
+ 0.167
+ ],
+ "y":[
+ 0.167
+ ]
+ },
+ "t":0,
+ "s":[
+ -159
+ ]
+ },
+ {
+ "t":360,
+ "s":[
+ 201
+ ]
+ }
+ ],
+ "ix":3
+ },
+ "m":1,
+ "ix":2,
+ "nm":"Trim Paths 1",
+ "mn":"ADBE Vector Filter - Trim",
+ "hd":false
}
],
- "ip": 0,
- "op": 600,
- "st": 0,
- "bm": 0
+ "ip":0,
+ "op":600,
+ "st":0,
+ "bm":0
},
{
- "ddd": 0,
- "ind": 2,
- "ty": 4,
- "nm": "Layer 1 Outlines 5",
- "sr": 1,
- "ks": {
- "o": {
- "a": 0,
- "k": 100,
- "ix": 11
+ "ddd":0,
+ "ind":7,
+ "ty":4,
+ "nm":"Fingerprint_20210701 Outlines 4",
+ "sr":1,
+ "ks":{
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":11
},
- "r": {
- "a": 0,
- "k": 0,
- "ix": 10
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":10
},
- "p": {
- "a": 0,
- "k": [
- 91.456,
- 92.206,
+ "p":{
+ "a":0,
+ "k":[
+ 23.091,
+ 32.5,
0
],
- "ix": 2,
- "l": 2
+ "ix":2,
+ "l":2
},
- "a": {
- "a": 0,
- "k": [
- 20,
- 25,
+ "a":{
+ "a":0,
+ "k":[
+ 19.341,
+ 24.25,
0
],
- "ix": 1,
- "l": 2
+ "ix":1,
+ "l":2
},
- "s": {
- "a": 0,
- "k": [
- 350,
- 350,
+ "s":{
+ "a":0,
+ "k":[
+ 100,
+ 100,
100
],
- "ix": 6,
- "l": 2
+ "ix":6,
+ "l":2
}
},
- "ao": 0,
- "shapes": [
+ "ao":0,
+ "shapes":[
{
- "ty": "gr",
- "it": [
+ "ty":"gr",
+ "it":[
{
- "ind": 0,
- "ty": "sh",
- "ix": 1,
- "ks": {
- "a": 0,
- "k": {
- "i": [
+ "ind":0,
+ "ty":"sh",
+ "ix":1,
+ "ks":{
+ "a":0,
+ "k":{
+ "i":[
[
0,
0
],
[
- -3.684,
+ 0,
0
],
[
- -2.883,
- -1.583
- ]
- ],
- "o": [
- [
- 2.883,
- -1.583
+ -6.53,
+ 0
],
[
- 3.683,
+ 0,
+ -5.793
+ ],
+ [
+ 0,
+ 0
+ ],
+ [
+ 2.159,
+ 0
+ ],
+ [
+ 0.59,
+ 1.489
+ ],
+ [
+ 0,
+ 0
+ ],
+ [
+ 1.587,
+ 0
+ ],
+ [
+ 0,
+ -2.16
+ ],
+ [
+ -0.81,
+ -1.363
+ ],
+ [
+ -0.844,
+ -0.674
+ ],
+ [
+ 0,
+ 0
+ ]
+ ],
+ "o":[
+ [
+ -0.753,
+ -2.095
+ ],
+ [
+ 0,
+ -5.793
+ ],
+ [
+ 6.529,
+ 0
+ ],
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 2.16
+ ],
+ [
+ -1.604,
+ 0
+ ],
+ [
+ 0,
+ 0
+ ],
+ [
+ -0.589,
+ -1.489
+ ],
+ [
+ -2.161,
+ 0
+ ],
+ [
+ 0,
+ 1.62
+ ],
+ [
+ 0.54,
+ 0.909
+ ],
+ [
+ 0,
0
],
[
@@ -352,254 +1801,374 @@
0
]
],
- "v": [
+ "v":[
[
- -10.417,
- 1.25
+ -10.702,
+ 5.728
+ ],
+ [
+ -11.454,
+ 1.506
],
[
0.001,
- -1.25
+ -9
],
[
- 10.417,
- 1.25
+ 11.454,
+ 1.506
+ ],
+ [
+ 11.454,
+ 1.817
+ ],
+ [
+ 7.544,
+ 5.728
+ ],
+ [
+ 3.926,
+ 3.273
+ ],
+ [
+ 2.618,
+ 0
+ ],
+ [
+ -0.997,
+ -2.454
+ ],
+ [
+ -4.91,
+ 1.457
+ ],
+ [
+ -3.657,
+ 6.014
+ ],
+ [
+ -1.57,
+ 8.412
+ ],
+ [
+ -0.818,
+ 9
]
],
- "c": false
+ "c":false
},
- "ix": 2
+ "ix":2
},
- "nm": "Path 1",
- "mn": "ADBE Vector Shape - Group",
- "hd": false
+ "nm":"Path 1",
+ "mn":"ADBE Vector Shape - Group",
+ "hd":false
},
{
- "ty": "tm",
- "s": {
- "a": 0,
- "k": 0,
- "ix": 1
- },
- "e": {
- "a": 0,
- "k": 54,
- "ix": 2
- },
- "o": {
- "a": 1,
- "k": [
- {
- "i": {
- "x": [
- 0.833
- ],
- "y": [
- 0.833
- ]
- },
- "o": {
- "x": [
- 0.167
- ],
- "y": [
- 0.167
- ]
- },
- "t": 0,
- "s": [
- 0
- ]
- },
- {
- "t": 360,
- "s": [
- 1080
- ]
- }
- ],
- "ix": 3
- },
- "m": 1,
- "ix": 2,
- "nm": "Trim Paths 1",
- "mn": "ADBE Vector Filter - Trim",
- "hd": false
- },
- {
- "ty": "st",
- "c": {
- "a": 0,
- "k": [
+ "ty":"st",
+ "c":{
+ "a":0,
+ "k":[
1,
1,
1,
1
],
- "ix": 3
+ "ix":3
},
- "o": {
- "a": 0,
- "k": 100,
- "ix": 4
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":4
},
- "w": {
- "a": 0,
- "k": 1,
- "ix": 5
+ "w":{
+ "a":0,
+ "k":1,
+ "ix":5
},
- "lc": 2,
- "lj": 1,
- "ml": 10,
- "bm": 0,
- "nm": "Stroke 1",
- "mn": "ADBE Vector Graphic - Stroke",
- "hd": false
+ "lc":2,
+ "lj":1,
+ "ml":10,
+ "bm":0,
+ "nm":"Stroke 1",
+ "mn":"ADBE Vector Graphic - Stroke",
+ "hd":false
},
{
- "ty": "tr",
- "p": {
- "a": 0,
- "k": [
- 19.999,
- 7.5
+ "ty":"tr",
+ "p":{
+ "a":0,
+ "k":[
+ 19.341,
+ 28.341
],
- "ix": 2
+ "ix":2
},
- "a": {
- "a": 0,
- "k": [
+ "a":{
+ "a":0,
+ "k":[
0,
0
],
- "ix": 1
+ "ix":1
},
- "s": {
- "a": 0,
- "k": [
+ "s":{
+ "a":0,
+ "k":[
100,
100
],
- "ix": 3
+ "ix":3
},
- "r": {
- "a": 0,
- "k": 0,
- "ix": 6
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":6
},
- "o": {
- "a": 0,
- "k": 100,
- "ix": 7
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":7
},
- "sk": {
- "a": 0,
- "k": 0,
- "ix": 4
+ "sk":{
+ "a":0,
+ "k":0,
+ "ix":4
},
- "sa": {
- "a": 0,
- "k": 0,
- "ix": 5
+ "sa":{
+ "a":0,
+ "k":0,
+ "ix":5
},
- "nm": "Transform"
+ "nm":"Transform"
}
],
- "nm": "Group 3",
- "np": 3,
- "cix": 2,
- "bm": 0,
- "ix": 1,
- "mn": "ADBE Vector Group",
- "hd": false
+ "nm":"Inside to dot ",
+ "np":2,
+ "cix":2,
+ "bm":0,
+ "ix":1,
+ "mn":"ADBE Vector Group",
+ "hd":false
+ },
+ {
+ "ty":"tm",
+ "s":{
+ "a":0,
+ "k":0,
+ "ix":1
+ },
+ "e":{
+ "a":0,
+ "k":9,
+ "ix":2
+ },
+ "o":{
+ "a":1,
+ "k":[
+ {
+ "i":{
+ "x":[
+ 0.833
+ ],
+ "y":[
+ 0.833
+ ]
+ },
+ "o":{
+ "x":[
+ 0.167
+ ],
+ "y":[
+ 0.167
+ ]
+ },
+ "t":0,
+ "s":[
+ 135
+ ]
+ },
+ {
+ "t":360,
+ "s":[
+ 495
+ ]
+ }
+ ],
+ "ix":3
+ },
+ "m":1,
+ "ix":2,
+ "nm":"Trim Paths 1",
+ "mn":"ADBE Vector Filter - Trim",
+ "hd":false
}
],
- "ip": 0,
- "op": 600,
- "st": 0,
- "bm": 0
+ "ip":0,
+ "op":600,
+ "st":0,
+ "bm":0
},
{
- "ddd": 0,
- "ind": 3,
- "ty": 4,
- "nm": "Layer 1 Outlines 8",
- "sr": 1,
- "ks": {
- "o": {
- "a": 0,
- "k": 100,
- "ix": 11
+ "ddd":0,
+ "ind":8,
+ "ty":4,
+ "nm":"Fingerprint_20210701 Outlines 3",
+ "sr":1,
+ "ks":{
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":11
},
- "r": {
- "a": 0,
- "k": 0,
- "ix": 10
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":10
},
- "p": {
- "a": 0,
- "k": [
- 91.456,
- 92.206,
+ "p":{
+ "a":0,
+ "k":[
+ 23.091,
+ 32.5,
0
],
- "ix": 2,
- "l": 2
+ "ix":2,
+ "l":2
},
- "a": {
- "a": 0,
- "k": [
- 20,
- 25,
+ "a":{
+ "a":0,
+ "k":[
+ 19.341,
+ 24.25,
0
],
- "ix": 1,
- "l": 2
+ "ix":1,
+ "l":2
},
- "s": {
- "a": 0,
- "k": [
- 350,
- 350,
+ "s":{
+ "a":0,
+ "k":[
+ 100,
+ 100,
100
],
- "ix": 6,
- "l": 2
+ "ix":6,
+ "l":2
}
},
- "ao": 0,
- "shapes": [
+ "ao":0,
+ "shapes":[
{
- "ty": "gr",
- "it": [
+ "ty":"gr",
+ "it":[
{
- "ind": 0,
- "ty": "sh",
- "ix": 1,
- "ks": {
- "a": 0,
- "k": {
- "i": [
+ "ind":0,
+ "ty":"sh",
+ "ix":1,
+ "ks":{
+ "a":0,
+ "k":{
+ "i":[
[
0,
0
],
[
- -5.883,
+ 0,
0
],
[
- -2.367,
- -3.933
- ]
- ],
- "o": [
- [
- 2.367,
- -3.933
+ -6.53,
+ 0
],
[
- 5.883,
+ 0,
+ -5.793
+ ],
+ [
+ 0,
+ 0
+ ],
+ [
+ 2.159,
+ 0
+ ],
+ [
+ 0.59,
+ 1.489
+ ],
+ [
+ 0,
+ 0
+ ],
+ [
+ 1.587,
+ 0
+ ],
+ [
+ 0,
+ -2.16
+ ],
+ [
+ -0.81,
+ -1.363
+ ],
+ [
+ -0.844,
+ -0.674
+ ],
+ [
+ 0,
+ 0
+ ]
+ ],
+ "o":[
+ [
+ -0.753,
+ -2.095
+ ],
+ [
+ 0,
+ -5.793
+ ],
+ [
+ 6.529,
+ 0
+ ],
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 2.16
+ ],
+ [
+ -1.604,
+ 0
+ ],
+ [
+ 0,
+ 0
+ ],
+ [
+ -0.589,
+ -1.489
+ ],
+ [
+ -2.161,
+ 0
+ ],
+ [
+ 0,
+ 1.62
+ ],
+ [
+ 0.54,
+ 0.909
+ ],
+ [
+ 0,
0
],
[
@@ -607,1839 +2176,527 @@
0
]
],
- "v": [
+ "v":[
[
- -13.75,
- 3.333
+ -10.702,
+ 5.728
],
[
- 0,
- -3.333
+ -11.454,
+ 1.506
],
[
- 13.75,
- 3.333
+ 0.001,
+ -9
+ ],
+ [
+ 11.454,
+ 1.506
+ ],
+ [
+ 11.454,
+ 1.817
+ ],
+ [
+ 7.544,
+ 5.728
+ ],
+ [
+ 3.926,
+ 3.273
+ ],
+ [
+ 2.618,
+ 0
+ ],
+ [
+ -0.997,
+ -2.454
+ ],
+ [
+ -4.91,
+ 1.457
+ ],
+ [
+ -3.657,
+ 6.014
+ ],
+ [
+ -1.57,
+ 8.412
+ ],
+ [
+ -0.818,
+ 9
]
],
- "c": false
+ "c":false
},
- "ix": 2
+ "ix":2
},
- "nm": "Path 1",
- "mn": "ADBE Vector Shape - Group",
- "hd": false
+ "nm":"Path 1",
+ "mn":"ADBE Vector Shape - Group",
+ "hd":false
},
{
- "ty": "tm",
- "s": {
- "a": 0,
- "k": 0,
- "ix": 1
- },
- "e": {
- "a": 0,
- "k": 38.235,
- "ix": 2
- },
- "o": {
- "a": 1,
- "k": [
- {
- "i": {
- "x": [
- 0.833
- ],
- "y": [
- 0.833
- ]
- },
- "o": {
- "x": [
- 0.167
- ],
- "y": [
- 0.167
- ]
- },
- "t": 0,
- "s": [
- 170
- ]
- },
- {
- "t": 360,
- "s": [
- 890
- ]
- }
- ],
- "ix": 3
- },
- "m": 1,
- "ix": 2,
- "nm": "Trim Paths 1",
- "mn": "ADBE Vector Filter - Trim",
- "hd": false
- },
- {
- "ty": "st",
- "c": {
- "a": 0,
- "k": [
+ "ty":"st",
+ "c":{
+ "a":0,
+ "k":[
1,
1,
1,
1
],
- "ix": 3
+ "ix":3
},
- "o": {
- "a": 0,
- "k": 100,
- "ix": 4
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":4
},
- "w": {
- "a": 0,
- "k": 1,
- "ix": 5
+ "w":{
+ "a":0,
+ "k":1,
+ "ix":5
},
- "lc": 2,
- "lj": 1,
- "ml": 10,
- "bm": 0,
- "nm": "Stroke 1",
- "mn": "ADBE Vector Graphic - Stroke",
- "hd": false
+ "lc":2,
+ "lj":1,
+ "ml":10,
+ "bm":0,
+ "nm":"Stroke 1",
+ "mn":"ADBE Vector Graphic - Stroke",
+ "hd":false
},
{
- "ty": "tr",
- "p": {
- "a": 0,
- "k": [
- 20,
- 16.25
+ "ty":"tr",
+ "p":{
+ "a":0,
+ "k":[
+ 19.341,
+ 28.341
],
- "ix": 2
+ "ix":2
},
- "a": {
- "a": 0,
- "k": [
+ "a":{
+ "a":0,
+ "k":[
0,
0
],
- "ix": 1
+ "ix":1
},
- "s": {
- "a": 0,
- "k": [
+ "s":{
+ "a":0,
+ "k":[
100,
100
],
- "ix": 3
+ "ix":3
},
- "r": {
- "a": 0,
- "k": 0,
- "ix": 6
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":6
},
- "o": {
- "a": 0,
- "k": 100,
- "ix": 7
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":7
},
- "sk": {
- "a": 0,
- "k": 0,
- "ix": 4
+ "sk":{
+ "a":0,
+ "k":0,
+ "ix":4
},
- "sa": {
- "a": 0,
- "k": 0,
- "ix": 5
+ "sa":{
+ "a":0,
+ "k":0,
+ "ix":5
},
- "nm": "Transform"
+ "nm":"Transform"
}
],
- "nm": "Group 2",
- "np": 3,
- "cix": 2,
- "bm": 0,
- "ix": 1,
- "mn": "ADBE Vector Group",
- "hd": false
+ "nm":"Inside to dot ",
+ "np":2,
+ "cix":2,
+ "bm":0,
+ "ix":1,
+ "mn":"ADBE Vector Group",
+ "hd":false
+ },
+ {
+ "ty":"tm",
+ "s":{
+ "a":0,
+ "k":0,
+ "ix":1
+ },
+ "e":{
+ "a":0,
+ "k":30,
+ "ix":2
+ },
+ "o":{
+ "a":1,
+ "k":[
+ {
+ "i":{
+ "x":[
+ 0.833
+ ],
+ "y":[
+ 0.833
+ ]
+ },
+ "o":{
+ "x":[
+ 0.167
+ ],
+ "y":[
+ 0.167
+ ]
+ },
+ "t":0,
+ "s":[
+ 0
+ ]
+ },
+ {
+ "t":360,
+ "s":[
+ 360
+ ]
+ }
+ ],
+ "ix":3
+ },
+ "m":1,
+ "ix":2,
+ "nm":"Trim Paths 1",
+ "mn":"ADBE Vector Filter - Trim",
+ "hd":false
}
],
- "ip": 0,
- "op": 600,
- "st": 0,
- "bm": 0
+ "ip":0,
+ "op":600,
+ "st":0,
+ "bm":0
},
{
- "ddd": 0,
- "ind": 4,
- "ty": 4,
- "nm": "Layer 1 Outlines 4",
- "sr": 1,
- "ks": {
- "o": {
- "a": 0,
- "k": 100,
- "ix": 11
+ "ddd":0,
+ "ind":9,
+ "ty":4,
+ "nm":"Fingerprint_20210701 Outlines",
+ "sr":1,
+ "ks":{
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":11
},
- "r": {
- "a": 0,
- "k": 0,
- "ix": 10
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":10
},
- "p": {
- "a": 0,
- "k": [
- 91.456,
- 92.206,
+ "p":{
+ "a":0,
+ "k":[
+ 23.091,
+ 32.5,
0
],
- "ix": 2,
- "l": 2
+ "ix":2,
+ "l":2
},
- "a": {
- "a": 0,
- "k": [
- 20,
- 25,
+ "a":{
+ "a":0,
+ "k":[
+ 19.341,
+ 24.25,
0
],
- "ix": 1,
- "l": 2
+ "ix":1,
+ "l":2
},
- "s": {
- "a": 0,
- "k": [
- 350,
- 350,
+ "s":{
+ "a":0,
+ "k":[
+ 100,
+ 100,
100
],
- "ix": 6,
- "l": 2
+ "ix":6,
+ "l":2
}
},
- "ao": 0,
- "shapes": [
+ "ao":0,
+ "shapes":[
{
- "ty": "gr",
- "it": [
+ "ty":"gr",
+ "it":[
{
- "ind": 0,
- "ty": "sh",
- "ix": 1,
- "ks": {
- "a": 0,
- "k": {
- "i": [
+ "ind":0,
+ "ty":"sh",
+ "ix":1,
+ "ks":{
+ "a":0,
+ "k":{
+ "i":[
[
0,
0
],
[
- -5.883,
+ 1.307,
+ -0.561
+ ],
+ [
+ 0.894,
+ -0.16
+ ],
+ [
+ 0.706,
0
],
[
- -2.367,
- -3.933
+ 0.844,
+ 0.193
+ ],
+ [
+ 0.728,
+ 0.334
+ ],
+ [
+ 0.967,
+ 0.901
]
],
- "o": [
+ "o":[
[
- 2.367,
- -3.933
+ -1.038,
+ 0.967
],
[
- 5.883,
+ -0.817,
+ 0.351
+ ],
+ [
+ -0.673,
+ 0.12
+ ],
+ [
+ -0.9,
0
],
[
+ -0.794,
+ -0.182
+ ],
+ [
+ -1.203,
+ -0.551
+ ],
+ [
0,
0
]
],
- "v": [
+ "v":[
[
- -13.75,
- 3.333
+ 8.182,
+ -1.636
],
[
- 0,
- -3.333
+ 4.642,
+ 0.681
],
[
- 13.75,
- 3.333
+ 2.07,
+ 1.453
+ ],
+ [
+ -0.001,
+ 1.636
+ ],
+ [
+ -2.621,
+ 1.341
+ ],
+ [
+ -4.909,
+ 0.563
+ ],
+ [
+ -8.182,
+ -1.636
]
],
- "c": false
+ "c":false
},
- "ix": 2
+ "ix":2
},
- "nm": "Path 1",
- "mn": "ADBE Vector Shape - Group",
- "hd": false
+ "nm":"Path 1",
+ "mn":"ADBE Vector Shape - Group",
+ "hd":false
},
{
- "ty": "tm",
- "s": {
- "a": 0,
- "k": 0,
- "ix": 1
- },
- "e": {
- "a": 0,
- "k": 34.235,
- "ix": 2
- },
- "o": {
- "a": 1,
- "k": [
- {
- "i": {
- "x": [
- 0.833
- ],
- "y": [
- 0.833
- ]
- },
- "o": {
- "x": [
- 0.167
- ],
- "y": [
- 0.167
- ]
- },
- "t": 0,
- "s": [
- 0
- ]
- },
- {
- "t": 360,
- "s": [
- 720
- ]
- }
- ],
- "ix": 3
- },
- "m": 1,
- "ix": 2,
- "nm": "Trim Paths 1",
- "mn": "ADBE Vector Filter - Trim",
- "hd": false
- },
- {
- "ty": "st",
- "c": {
- "a": 0,
- "k": [
+ "ty":"st",
+ "c":{
+ "a":0,
+ "k":[
1,
1,
1,
1
],
- "ix": 3
+ "ix":3
},
- "o": {
- "a": 0,
- "k": 100,
- "ix": 4
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":4
},
- "w": {
- "a": 0,
- "k": 1,
- "ix": 5
+ "w":{
+ "a":0,
+ "k":1,
+ "ix":5
},
- "lc": 2,
- "lj": 1,
- "ml": 10,
- "bm": 0,
- "nm": "Stroke 1",
- "mn": "ADBE Vector Graphic - Stroke",
- "hd": false
+ "lc":2,
+ "lj":1,
+ "ml":10,
+ "bm":0,
+ "nm":"Stroke 1",
+ "mn":"ADBE Vector Graphic - Stroke",
+ "hd":false
},
{
- "ty": "tr",
- "p": {
- "a": 0,
- "k": [
- 20,
- 16.25
+ "ty":"tr",
+ "p":{
+ "a":0,
+ "k":[
+ 19.341,
+ 40.614
],
- "ix": 2
+ "ix":2
},
- "a": {
- "a": 0,
- "k": [
+ "a":{
+ "a":0,
+ "k":[
0,
0
],
- "ix": 1
+ "ix":1
},
- "s": {
- "a": 0,
- "k": [
+ "s":{
+ "a":0,
+ "k":[
100,
100
],
- "ix": 3
+ "ix":3
},
- "r": {
- "a": 0,
- "k": 0,
- "ix": 6
+ "r":{
+ "a":0,
+ "k":0,
+ "ix":6
},
- "o": {
- "a": 0,
- "k": 100,
- "ix": 7
+ "o":{
+ "a":0,
+ "k":100,
+ "ix":7
},
- "sk": {
- "a": 0,
- "k": 0,
- "ix": 4
+ "sk":{
+ "a":0,
+ "k":0,
+ "ix":4
},
- "sa": {
- "a": 0,
- "k": 0,
- "ix": 5
+ "sa":{
+ "a":0,
+ "k":0,
+ "ix":5
},
- "nm": "Transform"
+ "nm":"Transform"
}
],
- "nm": "Group 2",
- "np": 3,
- "cix": 2,
- "bm": 0,
- "ix": 1,
- "mn": "ADBE Vector Group",
- "hd": false
- }
- ],
- "ip": 0,
- "op": 600,
- "st": 0,
- "bm": 0
- },
- {
- "ddd": 0,
- "ind": 5,
- "ty": 4,
- "nm": "Layer 1 Outlines 7",
- "sr": 1,
- "ks": {
- "o": {
- "a": 0,
- "k": 100,
- "ix": 11
+ "nm":"Bottom",
+ "np":2,
+ "cix":2,
+ "bm":0,
+ "ix":1,
+ "mn":"ADBE Vector Group",
+ "hd":false
},
- "r": {
- "a": 0,
- "k": 0,
- "ix": 10
- },
- "p": {
- "a": 0,
- "k": [
- 91.456,
- 92.206,
- 0
- ],
- "ix": 2,
- "l": 2
- },
- "a": {
- "a": 0,
- "k": [
- 20,
- 25,
- 0
- ],
- "ix": 1,
- "l": 2
- },
- "s": {
- "a": 0,
- "k": [
- 350,
- 350,
- 100
- ],
- "ix": 6,
- "l": 2
- }
- },
- "ao": 0,
- "shapes": [
{
- "ty": "gr",
- "it": [
- {
- "ind": 0,
- "ty": "sh",
- "ix": 1,
- "ks": {
- "a": 0,
- "k": {
- "i": [
- [
- 0,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- -6.65,
- 0
- ],
- [
- 0,
- -5.9
- ],
- [
- 0,
- 0
- ],
- [
- 2.333,
- 0
- ],
- [
- 0.633,
- 1.601
- ],
- [
- 0,
- 0
- ],
- [
- 1.717,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- 0,
- -2.2
- ],
- [
- -2.15,
- -1.716
- ],
- [
- 0,
- 0
- ]
+ "ty":"tm",
+ "s":{
+ "a":0,
+ "k":0,
+ "ix":1
+ },
+ "e":{
+ "a":0,
+ "k":69,
+ "ix":2
+ },
+ "o":{
+ "a":1,
+ "k":[
+ {
+ "i":{
+ "x":[
+ 0.833
],
- "o": [
- [
- -0.767,
- -2.134
- ],
- [
- 0,
- -5.917
- ],
- [
- 6.65,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- 0,
- 2.333
- ],
- [
- -1.734,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- -0.634,
- -1.599
- ],
- [
- 0,
- 0
- ],
- [
- -2.2,
- 0
- ],
- [
- 0,
- 2.75
- ],
- [
- 0,
- 0
- ],
- [
- 0,
- 0
- ]
- ],
- "v": [
- [
- -11.108,
- 5.825
- ],
- [
- -11.875,
- 1.525
- ],
- [
- -0.208,
- -9.175
- ],
- [
- 11.875,
- 1.525
- ],
- [
- 11.875,
- 1.592
- ],
- [
- 7.659,
- 5.808
- ],
- [
- 3.742,
- 3.158
- ],
- [
- 2.526,
- 0.141
- ],
- [
- -1.391,
- -2.508
- ],
- [
- -1.641,
- -2.508
- ],
- [
- -5.625,
- 1.475
- ],
- [
- -2.225,
- 8.558
- ],
- [
- -1.458,
- 9.175
- ]
- ],
- "c": false
+ "y":[
+ 0.833
+ ]
},
- "ix": 2
- },
- "nm": "Path 1",
- "mn": "ADBE Vector Shape - Group",
- "hd": false
- },
- {
- "ty": "tm",
- "s": {
- "a": 0,
- "k": 0,
- "ix": 1
- },
- "e": {
- "a": 0,
- "k": 35,
- "ix": 2
- },
- "o": {
- "a": 1,
- "k": [
- {
- "i": {
- "x": [
- 0.833
- ],
- "y": [
- 0.833
- ]
- },
- "o": {
- "x": [
- 0.167
- ],
- "y": [
- 0.167
- ]
- },
- "t": 0,
- "s": [
- -159
- ]
- },
- {
- "t": 360,
- "s": [
- 201
- ]
- }
- ],
- "ix": 3
- },
- "m": 1,
- "ix": 2,
- "nm": "Trim Paths 1",
- "mn": "ADBE Vector Filter - Trim",
- "hd": false
- },
- {
- "ty": "st",
- "c": {
- "a": 0,
- "k": [
- 1,
- 1,
- 1,
- 1
- ],
- "ix": 3
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 4
- },
- "w": {
- "a": 0,
- "k": 1,
- "ix": 5
- },
- "lc": 2,
- "lj": 1,
- "ml": 4,
- "bm": 0,
- "nm": "Stroke 1",
- "mn": "ADBE Vector Graphic - Stroke",
- "hd": false
- },
- {
- "ty": "tr",
- "p": {
- "a": 0,
- "k": [
- 19.992,
- 28.758
- ],
- "ix": 2
- },
- "a": {
- "a": 0,
- "k": [
- 0,
+ "o":{
+ "x":[
+ 0.167
+ ],
+ "y":[
+ 0.167
+ ]
+ },
+ "t":0,
+ "s":[
0
- ],
- "ix": 1
+ ]
},
- "s": {
- "a": 0,
- "k": [
- 100,
- 100
- ],
- "ix": 3
- },
- "r": {
- "a": 0,
- "k": 0,
- "ix": 6
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 7
- },
- "sk": {
- "a": 0,
- "k": 0,
- "ix": 4
- },
- "sa": {
- "a": 0,
- "k": 0,
- "ix": 5
- },
- "nm": "Transform"
- }
- ],
- "nm": "Group 4",
- "np": 3,
- "cix": 2,
- "bm": 0,
- "ix": 1,
- "mn": "ADBE Vector Group",
- "hd": false
+ {
+ "t":360,
+ "s":[
+ 720
+ ]
+ }
+ ],
+ "ix":3
+ },
+ "m":1,
+ "ix":2,
+ "nm":"Trim Paths 1",
+ "mn":"ADBE Vector Filter - Trim",
+ "hd":false
}
],
- "ip": 0,
- "op": 600,
- "st": 0,
- "bm": 0
- },
- {
- "ddd": 0,
- "ind": 6,
- "ty": 4,
- "nm": "Layer 1 Outlines 6",
- "sr": 1,
- "ks": {
- "o": {
- "a": 0,
- "k": 100,
- "ix": 11
- },
- "r": {
- "a": 0,
- "k": 0,
- "ix": 10
- },
- "p": {
- "a": 0,
- "k": [
- 91.456,
- 92.206,
- 0
- ],
- "ix": 2,
- "l": 2
- },
- "a": {
- "a": 0,
- "k": [
- 20,
- 25,
- 0
- ],
- "ix": 1,
- "l": 2
- },
- "s": {
- "a": 0,
- "k": [
- 350,
- 350,
- 100
- ],
- "ix": 6,
- "l": 2
- }
- },
- "ao": 0,
- "shapes": [
- {
- "ty": "gr",
- "it": [
- {
- "ind": 0,
- "ty": "sh",
- "ix": 1,
- "ks": {
- "a": 0,
- "k": {
- "i": [
- [
- 0,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- -6.65,
- 0
- ],
- [
- 0,
- -5.9
- ],
- [
- 0,
- 0
- ],
- [
- 2.333,
- 0
- ],
- [
- 0.633,
- 1.601
- ],
- [
- 0,
- 0
- ],
- [
- 1.717,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- 0,
- -2.2
- ],
- [
- -2.15,
- -1.716
- ],
- [
- 0,
- 0
- ]
- ],
- "o": [
- [
- -0.767,
- -2.134
- ],
- [
- 0,
- -5.917
- ],
- [
- 6.65,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- 0,
- 2.333
- ],
- [
- -1.734,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- -0.634,
- -1.599
- ],
- [
- 0,
- 0
- ],
- [
- -2.2,
- 0
- ],
- [
- 0,
- 2.75
- ],
- [
- 0,
- 0
- ],
- [
- 0,
- 0
- ]
- ],
- "v": [
- [
- -11.108,
- 5.825
- ],
- [
- -11.875,
- 1.525
- ],
- [
- -0.208,
- -9.175
- ],
- [
- 11.875,
- 1.525
- ],
- [
- 11.875,
- 1.592
- ],
- [
- 7.659,
- 5.808
- ],
- [
- 3.742,
- 3.158
- ],
- [
- 2.526,
- 0.141
- ],
- [
- -1.391,
- -2.508
- ],
- [
- -1.641,
- -2.508
- ],
- [
- -5.625,
- 1.475
- ],
- [
- -2.225,
- 8.558
- ],
- [
- -1.458,
- 9.175
- ]
- ],
- "c": false
- },
- "ix": 2
- },
- "nm": "Path 1",
- "mn": "ADBE Vector Shape - Group",
- "hd": false
- },
- {
- "ty": "tm",
- "s": {
- "a": 0,
- "k": 0,
- "ix": 1
- },
- "e": {
- "a": 0,
- "k": 9,
- "ix": 2
- },
- "o": {
- "a": 1,
- "k": [
- {
- "i": {
- "x": [
- 0.833
- ],
- "y": [
- 0.833
- ]
- },
- "o": {
- "x": [
- 0.167
- ],
- "y": [
- 0.167
- ]
- },
- "t": 0,
- "s": [
- 135
- ]
- },
- {
- "t": 360,
- "s": [
- 495
- ]
- }
- ],
- "ix": 3
- },
- "m": 1,
- "ix": 2,
- "nm": "Trim Paths 1",
- "mn": "ADBE Vector Filter - Trim",
- "hd": false
- },
- {
- "ty": "st",
- "c": {
- "a": 0,
- "k": [
- 1,
- 1,
- 1,
- 1
- ],
- "ix": 3
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 4
- },
- "w": {
- "a": 0,
- "k": 1,
- "ix": 5
- },
- "lc": 2,
- "lj": 1,
- "ml": 4,
- "bm": 0,
- "nm": "Stroke 1",
- "mn": "ADBE Vector Graphic - Stroke",
- "hd": false
- },
- {
- "ty": "tr",
- "p": {
- "a": 0,
- "k": [
- 19.992,
- 28.758
- ],
- "ix": 2
- },
- "a": {
- "a": 0,
- "k": [
- 0,
- 0
- ],
- "ix": 1
- },
- "s": {
- "a": 0,
- "k": [
- 100,
- 100
- ],
- "ix": 3
- },
- "r": {
- "a": 0,
- "k": 0,
- "ix": 6
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 7
- },
- "sk": {
- "a": 0,
- "k": 0,
- "ix": 4
- },
- "sa": {
- "a": 0,
- "k": 0,
- "ix": 5
- },
- "nm": "Transform"
- }
- ],
- "nm": "Group 4",
- "np": 3,
- "cix": 2,
- "bm": 0,
- "ix": 1,
- "mn": "ADBE Vector Group",
- "hd": false
- }
- ],
- "ip": 0,
- "op": 600,
- "st": 0,
- "bm": 0
- },
- {
- "ddd": 0,
- "ind": 7,
- "ty": 4,
- "nm": "Layer 1 Outlines 3",
- "sr": 1,
- "ks": {
- "o": {
- "a": 0,
- "k": 100,
- "ix": 11
- },
- "r": {
- "a": 0,
- "k": 0,
- "ix": 10
- },
- "p": {
- "a": 0,
- "k": [
- 91.456,
- 92.206,
- 0
- ],
- "ix": 2,
- "l": 2
- },
- "a": {
- "a": 0,
- "k": [
- 20,
- 25,
- 0
- ],
- "ix": 1,
- "l": 2
- },
- "s": {
- "a": 0,
- "k": [
- 350,
- 350,
- 100
- ],
- "ix": 6,
- "l": 2
- }
- },
- "ao": 0,
- "shapes": [
- {
- "ty": "gr",
- "it": [
- {
- "ind": 0,
- "ty": "sh",
- "ix": 1,
- "ks": {
- "a": 0,
- "k": {
- "i": [
- [
- 0,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- -6.65,
- 0
- ],
- [
- 0,
- -5.9
- ],
- [
- 0,
- 0
- ],
- [
- 2.333,
- 0
- ],
- [
- 0.633,
- 1.601
- ],
- [
- 0,
- 0
- ],
- [
- 1.717,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- 0,
- -2.2
- ],
- [
- -2.15,
- -1.716
- ],
- [
- 0,
- 0
- ]
- ],
- "o": [
- [
- -0.767,
- -2.134
- ],
- [
- 0,
- -5.917
- ],
- [
- 6.65,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- 0,
- 2.333
- ],
- [
- -1.734,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- -0.634,
- -1.599
- ],
- [
- 0,
- 0
- ],
- [
- -2.2,
- 0
- ],
- [
- 0,
- 2.75
- ],
- [
- 0,
- 0
- ],
- [
- 0,
- 0
- ]
- ],
- "v": [
- [
- -11.108,
- 5.825
- ],
- [
- -11.875,
- 1.525
- ],
- [
- -0.208,
- -9.175
- ],
- [
- 11.875,
- 1.525
- ],
- [
- 11.875,
- 1.592
- ],
- [
- 7.659,
- 5.808
- ],
- [
- 3.742,
- 3.158
- ],
- [
- 2.526,
- 0.141
- ],
- [
- -1.391,
- -2.508
- ],
- [
- -1.641,
- -2.508
- ],
- [
- -5.625,
- 1.475
- ],
- [
- -2.225,
- 8.558
- ],
- [
- -1.458,
- 9.175
- ]
- ],
- "c": false
- },
- "ix": 2
- },
- "nm": "Path 1",
- "mn": "ADBE Vector Shape - Group",
- "hd": false
- },
- {
- "ty": "tm",
- "s": {
- "a": 0,
- "k": 0,
- "ix": 1
- },
- "e": {
- "a": 0,
- "k": 30,
- "ix": 2
- },
- "o": {
- "a": 1,
- "k": [
- {
- "i": {
- "x": [
- 0.833
- ],
- "y": [
- 0.833
- ]
- },
- "o": {
- "x": [
- 0.167
- ],
- "y": [
- 0.167
- ]
- },
- "t": 0,
- "s": [
- 0
- ]
- },
- {
- "t": 360,
- "s": [
- 360
- ]
- }
- ],
- "ix": 3
- },
- "m": 1,
- "ix": 2,
- "nm": "Trim Paths 1",
- "mn": "ADBE Vector Filter - Trim",
- "hd": false
- },
- {
- "ty": "st",
- "c": {
- "a": 0,
- "k": [
- 1,
- 1,
- 1,
- 1
- ],
- "ix": 3
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 4
- },
- "w": {
- "a": 0,
- "k": 1,
- "ix": 5
- },
- "lc": 2,
- "lj": 1,
- "ml": 4,
- "bm": 0,
- "nm": "Stroke 1",
- "mn": "ADBE Vector Graphic - Stroke",
- "hd": false
- },
- {
- "ty": "tr",
- "p": {
- "a": 0,
- "k": [
- 19.992,
- 28.758
- ],
- "ix": 2
- },
- "a": {
- "a": 0,
- "k": [
- 0,
- 0
- ],
- "ix": 1
- },
- "s": {
- "a": 0,
- "k": [
- 100,
- 100
- ],
- "ix": 3
- },
- "r": {
- "a": 0,
- "k": 0,
- "ix": 6
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 7
- },
- "sk": {
- "a": 0,
- "k": 0,
- "ix": 4
- },
- "sa": {
- "a": 0,
- "k": 0,
- "ix": 5
- },
- "nm": "Transform"
- }
- ],
- "nm": "Group 4",
- "np": 3,
- "cix": 2,
- "bm": 0,
- "ix": 1,
- "mn": "ADBE Vector Group",
- "hd": false
- }
- ],
- "ip": 0,
- "op": 600,
- "st": 0,
- "bm": 0
- },
- {
- "ddd": 0,
- "ind": 8,
- "ty": 4,
- "nm": "Layer 1 Outlines 2",
- "sr": 1,
- "ks": {
- "o": {
- "a": 0,
- "k": 100,
- "ix": 11
- },
- "r": {
- "a": 0,
- "k": 0,
- "ix": 10
- },
- "p": {
- "a": 0,
- "k": [
- 91.456,
- 92.206,
- 0
- ],
- "ix": 2,
- "l": 2
- },
- "a": {
- "a": 0,
- "k": [
- 20,
- 25,
- 0
- ],
- "ix": 1,
- "l": 2
- },
- "s": {
- "a": 0,
- "k": [
- 350,
- 350,
- 100
- ],
- "ix": 6,
- "l": 2
- }
- },
- "ao": 0,
- "shapes": [
- {
- "ty": "gr",
- "it": [
- {
- "ind": 0,
- "ty": "sh",
- "ix": 1,
- "ks": {
- "a": 0,
- "k": {
- "i": [
- [
- 0,
- 0
- ],
- [
- 3.2,
- 0
- ],
- [
- 2.217,
- 2.066
- ]
- ],
- "o": [
- [
- -2.217,
- 2.066
- ],
- [
- -3.2,
- 0
- ],
- [
- 0,
- 0
- ]
- ],
- "v": [
- [
- 8.75,
- -1.667
- ],
- [
- 0,
- 1.667
- ],
- [
- -8.75,
- -1.667
- ]
- ],
- "c": false
- },
- "ix": 2
- },
- "nm": "Path 1",
- "mn": "ADBE Vector Shape - Group",
- "hd": false
- },
- {
- "ty": "tm",
- "s": {
- "a": 0,
- "k": 0,
- "ix": 1
- },
- "e": {
- "a": 0,
- "k": 69,
- "ix": 2
- },
- "o": {
- "a": 1,
- "k": [
- {
- "i": {
- "x": [
- 0.833
- ],
- "y": [
- 0.833
- ]
- },
- "o": {
- "x": [
- 0.167
- ],
- "y": [
- 0.167
- ]
- },
- "t": 0,
- "s": [
- 0
- ]
- },
- {
- "t": 360,
- "s": [
- 720
- ]
- }
- ],
- "ix": 3
- },
- "m": 1,
- "ix": 2,
- "nm": "Trim Paths 1",
- "mn": "ADBE Vector Filter - Trim",
- "hd": false
- },
- {
- "ty": "st",
- "c": {
- "a": 0,
- "k": [
- 1,
- 1,
- 1,
- 1
- ],
- "ix": 3
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 4
- },
- "w": {
- "a": 0,
- "k": 1,
- "ix": 5
- },
- "lc": 2,
- "lj": 1,
- "ml": 10,
- "bm": 0,
- "d": [
- {
- "n": "d",
- "nm": "dash",
- "v": {
- "a": 0,
- "k": 0,
- "ix": 1
- }
- },
- {
- "n": "o",
- "nm": "offset",
- "v": {
- "a": 0,
- "k": 25,
- "ix": 7
- }
- }
- ],
- "nm": "Stroke 1",
- "mn": "ADBE Vector Graphic - Stroke",
- "hd": false
- },
- {
- "ty": "tr",
- "p": {
- "a": 0,
- "k": [
- 20,
- 42.083
- ],
- "ix": 2
- },
- "a": {
- "a": 0,
- "k": [
- 0,
- 0
- ],
- "ix": 1
- },
- "s": {
- "a": 0,
- "k": [
- 100,
- 100
- ],
- "ix": 3
- },
- "r": {
- "a": 0,
- "k": 0,
- "ix": 6
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 7
- },
- "sk": {
- "a": 0,
- "k": 0,
- "ix": 4
- },
- "sa": {
- "a": 0,
- "k": 0,
- "ix": 5
- },
- "nm": "Transform"
- }
- ],
- "nm": "Group 1",
- "np": 3,
- "cix": 2,
- "bm": 0,
- "ix": 1,
- "mn": "ADBE Vector Group",
- "hd": false
- }
- ],
- "ip": 0,
- "op": 600,
- "st": 0,
- "bm": 0
+ "ip":0,
+ "op":600,
+ "st":0,
+ "bm":0
}
],
- "markers": [
+ "markers":[
{
- "tm": 210,
- "cm": "2",
- "dr": 0
+ "tm":210,
+ "cm":"2",
+ "dr":0
},
{
- "tm": 255,
- "cm": "1",
- "dr": 0
+ "tm":255,
+ "cm":"1",
+ "dr":0
}
]
}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/udfps_lockscreen_fp.json b/packages/SystemUI/res/raw/udfps_lockscreen_fp.json
index cef433e..a25a475 100644
--- a/packages/SystemUI/res/raw/udfps_lockscreen_fp.json
+++ b/packages/SystemUI/res/raw/udfps_lockscreen_fp.json
@@ -1,1017 +1 @@
-{
- "v": "5.7.8",
- "fr": 60,
- "ip": 0,
- "op": 46,
- "w": 180,
- "h": 185,
- "nm": "fingerprint_build_on",
- "ddd": 0,
- "assets": [],
- "layers": [
- {
- "ddd": 0,
- "ind": 1,
- "ty": 4,
- "nm": "fingerprint_build_on",
- "sr": 1,
- "ks": {
- "o": {
- "a": 0,
- "k": 100,
- "ix": 11
- },
- "r": {
- "a": 0,
- "k": 0,
- "ix": 10
- },
- "p": {
- "a": 0,
- "k": [
- 91.456,
- 92.206,
- 0
- ],
- "ix": 2,
- "l": 2
- },
- "a": {
- "a": 0,
- "k": [
- 20,
- 25,
- 0
- ],
- "ix": 1,
- "l": 2
- },
- "s": {
- "a": 0,
- "k": [
- 350,
- 350,
- 100
- ],
- "ix": 6,
- "l": 2
- }
- },
- "ao": 0,
- "shapes": [
- {
- "ty": "gr",
- "it": [
- {
- "ind": 0,
- "ty": "sh",
- "ix": 1,
- "ks": {
- "a": 0,
- "k": {
- "i": [
- [
- 0,
- 0
- ],
- [
- 3.2,
- 0
- ],
- [
- 2.217,
- 2.066
- ]
- ],
- "o": [
- [
- -2.217,
- 2.066
- ],
- [
- -3.2,
- 0
- ],
- [
- 0,
- 0
- ]
- ],
- "v": [
- [
- 8.75,
- -1.667
- ],
- [
- 0,
- 1.667
- ],
- [
- -8.75,
- -1.667
- ]
- ],
- "c": false
- },
- "ix": 2
- },
- "nm": "Path 1",
- "mn": "ADBE Vector Shape - Group",
- "hd": false
- },
- {
- "ty": "tm",
- "s": {
- "a": 0,
- "k": 0,
- "ix": 1
- },
- "e": {
- "a": 0,
- "k": 100,
- "ix": 2
- },
- "o": {
- "a": 0,
- "k": 0,
- "ix": 3
- },
- "m": 1,
- "ix": 2,
- "nm": "Trim Paths 1",
- "mn": "ADBE Vector Filter - Trim",
- "hd": false
- },
- {
- "ty": "st",
- "c": {
- "a": 0,
- "k": [
- 1,
- 1,
- 1,
- 1
- ],
- "ix": 3
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 4
- },
- "w": {
- "a": 1,
- "k": [
- {
- "i": {
- "x": [
- 0
- ],
- "y": [
- 1
- ]
- },
- "o": {
- "x": [
- 0.167
- ],
- "y": [
- 0.167
- ]
- },
- "t": 0,
- "s": [
- 0
- ]
- },
- {
- "t": 24,
- "s": [
- 2.5
- ]
- }
- ],
- "ix": 5
- },
- "lc": 2,
- "lj": 1,
- "ml": 10,
- "bm": 0,
- "d": [
- {
- "n": "d",
- "nm": "dash",
- "v": {
- "a": 0,
- "k": 0,
- "ix": 1
- }
- },
- {
- "n": "o",
- "nm": "offset",
- "v": {
- "a": 0,
- "k": 0,
- "ix": 7
- }
- }
- ],
- "nm": "Stroke 1",
- "mn": "ADBE Vector Graphic - Stroke",
- "hd": false
- },
- {
- "ty": "tr",
- "p": {
- "a": 0,
- "k": [
- 20,
- 42.083
- ],
- "ix": 2
- },
- "a": {
- "a": 0,
- "k": [
- 0,
- 0
- ],
- "ix": 1
- },
- "s": {
- "a": 0,
- "k": [
- 100,
- 100
- ],
- "ix": 3
- },
- "r": {
- "a": 0,
- "k": 0,
- "ix": 6
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 7
- },
- "sk": {
- "a": 0,
- "k": 0,
- "ix": 4
- },
- "sa": {
- "a": 0,
- "k": 0,
- "ix": 5
- },
- "nm": "Transform"
- }
- ],
- "nm": "Group 1",
- "np": 3,
- "cix": 2,
- "bm": 0,
- "ix": 1,
- "mn": "ADBE Vector Group",
- "hd": false
- },
- {
- "ty": "gr",
- "it": [
- {
- "ind": 0,
- "ty": "sh",
- "ix": 1,
- "ks": {
- "a": 0,
- "k": {
- "i": [
- [
- 0,
- 0
- ],
- [
- -5.883,
- 0
- ],
- [
- -2.367,
- -3.933
- ]
- ],
- "o": [
- [
- 2.367,
- -3.933
- ],
- [
- 5.883,
- 0
- ],
- [
- 0,
- 0
- ]
- ],
- "v": [
- [
- -13.75,
- 3.333
- ],
- [
- 0,
- -3.333
- ],
- [
- 13.75,
- 3.333
- ]
- ],
- "c": false
- },
- "ix": 2
- },
- "nm": "Path 1",
- "mn": "ADBE Vector Shape - Group",
- "hd": false
- },
- {
- "ty": "tm",
- "s": {
- "a": 0,
- "k": 0,
- "ix": 1
- },
- "e": {
- "a": 0,
- "k": 100,
- "ix": 2
- },
- "o": {
- "a": 0,
- "k": 0,
- "ix": 3
- },
- "m": 1,
- "ix": 2,
- "nm": "Trim Paths 1",
- "mn": "ADBE Vector Filter - Trim",
- "hd": false
- },
- {
- "ty": "st",
- "c": {
- "a": 0,
- "k": [
- 1,
- 1,
- 1,
- 1
- ],
- "ix": 3
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 4
- },
- "w": {
- "a": 1,
- "k": [
- {
- "i": {
- "x": [
- 0
- ],
- "y": [
- 1
- ]
- },
- "o": {
- "x": [
- 0.167
- ],
- "y": [
- 0.167
- ]
- },
- "t": 0,
- "s": [
- 0
- ]
- },
- {
- "t": 24,
- "s": [
- 2.5
- ]
- }
- ],
- "ix": 5
- },
- "lc": 2,
- "lj": 1,
- "ml": 10,
- "bm": 0,
- "nm": "Stroke 1",
- "mn": "ADBE Vector Graphic - Stroke",
- "hd": false
- },
- {
- "ty": "tr",
- "p": {
- "a": 0,
- "k": [
- 20,
- 16.25
- ],
- "ix": 2
- },
- "a": {
- "a": 0,
- "k": [
- 0,
- 0
- ],
- "ix": 1
- },
- "s": {
- "a": 0,
- "k": [
- 100,
- 100
- ],
- "ix": 3
- },
- "r": {
- "a": 0,
- "k": 0,
- "ix": 6
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 7
- },
- "sk": {
- "a": 0,
- "k": 0,
- "ix": 4
- },
- "sa": {
- "a": 0,
- "k": 0,
- "ix": 5
- },
- "nm": "Transform"
- }
- ],
- "nm": "Group 2",
- "np": 3,
- "cix": 2,
- "bm": 0,
- "ix": 2,
- "mn": "ADBE Vector Group",
- "hd": false
- },
- {
- "ty": "gr",
- "it": [
- {
- "ind": 0,
- "ty": "sh",
- "ix": 1,
- "ks": {
- "a": 0,
- "k": {
- "i": [
- [
- 0,
- 0
- ],
- [
- -3.684,
- 0
- ],
- [
- -2.883,
- -1.583
- ]
- ],
- "o": [
- [
- 2.883,
- -1.583
- ],
- [
- 3.683,
- 0
- ],
- [
- 0,
- 0
- ]
- ],
- "v": [
- [
- -10.417,
- 1.25
- ],
- [
- 0.001,
- -1.25
- ],
- [
- 10.417,
- 1.25
- ]
- ],
- "c": false
- },
- "ix": 2
- },
- "nm": "Path 1",
- "mn": "ADBE Vector Shape - Group",
- "hd": false
- },
- {
- "ty": "tm",
- "s": {
- "a": 0,
- "k": 0,
- "ix": 1
- },
- "e": {
- "a": 0,
- "k": 100,
- "ix": 2
- },
- "o": {
- "a": 0,
- "k": 0,
- "ix": 3
- },
- "m": 1,
- "ix": 2,
- "nm": "Trim Paths 1",
- "mn": "ADBE Vector Filter - Trim",
- "hd": false
- },
- {
- "ty": "st",
- "c": {
- "a": 0,
- "k": [
- 1,
- 1,
- 1,
- 1
- ],
- "ix": 3
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 4
- },
- "w": {
- "a": 1,
- "k": [
- {
- "i": {
- "x": [
- 0
- ],
- "y": [
- 1
- ]
- },
- "o": {
- "x": [
- 0.167
- ],
- "y": [
- 0.167
- ]
- },
- "t": 0,
- "s": [
- 0
- ]
- },
- {
- "t": 24,
- "s": [
- 2.5
- ]
- }
- ],
- "ix": 5
- },
- "lc": 2,
- "lj": 1,
- "ml": 10,
- "bm": 0,
- "nm": "Stroke 1",
- "mn": "ADBE Vector Graphic - Stroke",
- "hd": false
- },
- {
- "ty": "tr",
- "p": {
- "a": 0,
- "k": [
- 19.999,
- 7.5
- ],
- "ix": 2
- },
- "a": {
- "a": 0,
- "k": [
- 0,
- 0
- ],
- "ix": 1
- },
- "s": {
- "a": 0,
- "k": [
- 100,
- 100
- ],
- "ix": 3
- },
- "r": {
- "a": 0,
- "k": 0,
- "ix": 6
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 7
- },
- "sk": {
- "a": 0,
- "k": 0,
- "ix": 4
- },
- "sa": {
- "a": 0,
- "k": 0,
- "ix": 5
- },
- "nm": "Transform"
- }
- ],
- "nm": "Group 3",
- "np": 3,
- "cix": 2,
- "bm": 0,
- "ix": 3,
- "mn": "ADBE Vector Group",
- "hd": false
- },
- {
- "ty": "gr",
- "it": [
- {
- "ind": 0,
- "ty": "sh",
- "ix": 1,
- "ks": {
- "a": 0,
- "k": {
- "i": [
- [
- 0,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- -6.65,
- 0
- ],
- [
- 0,
- -5.9
- ],
- [
- 0,
- 0
- ],
- [
- 2.333,
- 0
- ],
- [
- 0.633,
- 1.601
- ],
- [
- 0,
- 0
- ],
- [
- 1.717,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- 0,
- -2.2
- ],
- [
- -2.15,
- -1.716
- ],
- [
- 0,
- 0
- ]
- ],
- "o": [
- [
- -0.767,
- -2.134
- ],
- [
- 0,
- -5.917
- ],
- [
- 6.65,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- 0,
- 2.333
- ],
- [
- -1.734,
- 0
- ],
- [
- 0,
- 0
- ],
- [
- -0.634,
- -1.599
- ],
- [
- 0,
- 0
- ],
- [
- -2.2,
- 0
- ],
- [
- 0,
- 2.75
- ],
- [
- 0,
- 0
- ],
- [
- 0,
- 0
- ]
- ],
- "v": [
- [
- -11.108,
- 5.825
- ],
- [
- -11.875,
- 1.525
- ],
- [
- -0.208,
- -9.175
- ],
- [
- 11.875,
- 1.525
- ],
- [
- 11.875,
- 1.592
- ],
- [
- 7.659,
- 5.808
- ],
- [
- 3.742,
- 3.158
- ],
- [
- 2.526,
- 0.141
- ],
- [
- -1.391,
- -2.508
- ],
- [
- -1.641,
- -2.508
- ],
- [
- -5.625,
- 1.475
- ],
- [
- -2.225,
- 8.558
- ],
- [
- -1.458,
- 9.175
- ]
- ],
- "c": false
- },
- "ix": 2
- },
- "nm": "Path 1",
- "mn": "ADBE Vector Shape - Group",
- "hd": false
- },
- {
- "ty": "tm",
- "s": {
- "a": 0,
- "k": 0,
- "ix": 1
- },
- "e": {
- "a": 0,
- "k": 100,
- "ix": 2
- },
- "o": {
- "a": 0,
- "k": 0,
- "ix": 3
- },
- "m": 1,
- "ix": 2,
- "nm": "Trim Paths 1",
- "mn": "ADBE Vector Filter - Trim",
- "hd": false
- },
- {
- "ty": "st",
- "c": {
- "a": 0,
- "k": [
- 1,
- 1,
- 1,
- 1
- ],
- "ix": 3
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 4
- },
- "w": {
- "a": 1,
- "k": [
- {
- "i": {
- "x": [
- 0
- ],
- "y": [
- 1
- ]
- },
- "o": {
- "x": [
- 0.167
- ],
- "y": [
- 0.167
- ]
- },
- "t": 0,
- "s": [
- 0
- ]
- },
- {
- "t": 24,
- "s": [
- 2.5
- ]
- }
- ],
- "ix": 5
- },
- "lc": 2,
- "lj": 1,
- "ml": 10,
- "bm": 0,
- "nm": "Stroke 1",
- "mn": "ADBE Vector Graphic - Stroke",
- "hd": false
- },
- {
- "ty": "tr",
- "p": {
- "a": 0,
- "k": [
- 19.992,
- 28.758
- ],
- "ix": 2
- },
- "a": {
- "a": 0,
- "k": [
- 0,
- 0
- ],
- "ix": 1
- },
- "s": {
- "a": 0,
- "k": [
- 100,
- 100
- ],
- "ix": 3
- },
- "r": {
- "a": 0,
- "k": 0,
- "ix": 6
- },
- "o": {
- "a": 0,
- "k": 100,
- "ix": 7
- },
- "sk": {
- "a": 0,
- "k": 0,
- "ix": 4
- },
- "sa": {
- "a": 0,
- "k": 0,
- "ix": 5
- },
- "nm": "Transform"
- }
- ],
- "nm": "Group 4",
- "np": 3,
- "cix": 2,
- "bm": 0,
- "ix": 4,
- "mn": "ADBE Vector Group",
- "hd": false
- }
- ],
- "ip": 0,
- "op": 600,
- "st": 0,
- "bm": 0
- }
- ],
- "markers": [
- {
- "tm": 210,
- "cm": "2",
- "dr": 0
- },
- {
- "tm": 255,
- "cm": "1",
- "dr": 0
- }
- ]
-}
\ No newline at end of file
+{"v":"5.7.8","fr":60,"ip":0,"op":46,"w":46,"h":65,"nm":"fingerprint_build_on","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Fingerprint_20210701 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[23.091,32.5,0],"ix":2,"l":2},"a":{"a":0,"k":[19.341,24.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.701,0.42],[-1.757,0],[-1.577,-0.381],[-1.485,-0.816]],"o":[[1.455,-0.799],[1.608,-0.397],[1.719,0],[1.739,0.42],[0,0]],"v":[[-9.818,1.227],[-5.064,-0.618],[0,-1.227],[4.96,-0.643],[9.818,1.227]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,7.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.446,1.161],[-1.168,0.275],[-1.439,0],[-1.301,-0.304],[-1.225,-0.66],[-1.11,-1.844]],"o":[[1.23,-2.044],[1.024,-0.486],[1.312,-0.31],[1.425,0],[1.454,0.34],[2.122,1.143],[0,0]],"v":[[-13.091,3.273],[-7.438,-1.646],[-4.14,-2.797],[0,-3.273],[4.104,-2.805],[8.141,-1.29],[13.091,3.273]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,16.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Mid Top","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-6.53,0],[0,-5.793],[0,0],[2.159,0],[0.59,1.489],[0,0],[1.587,0],[0,-2.16],[-0.81,-1.363],[-0.844,-0.674],[0,0]],"o":[[-0.753,-2.095],[0,-5.793],[6.529,0],[0,0],[0,2.16],[-1.604,0],[0,0],[-0.589,-1.489],[-2.161,0],[0,1.62],[0.54,0.909],[0,0],[0,0]],"v":[[-10.702,5.728],[-11.454,1.506],[0.001,-9],[11.454,1.506],[11.454,1.817],[7.544,5.728],[3.926,3.273],[2.618,0],[-0.997,-2.454],[-4.91,1.457],[-3.657,6.014],[-1.57,8.412],[-0.818,9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.949000000954,0.624000012875,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,28.341],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Inside to dot ","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.307,-0.561],[0.894,-0.16],[0.706,0],[0.844,0.193],[0.728,0.334],[0.967,0.901]],"o":[[-1.038,0.967],[-0.817,0.351],[-0.673,0.12],[-0.9,0],[-0.794,-0.182],[-1.203,-0.551],[0,0]],"v":[[8.182,-1.636],[4.642,0.681],[2.07,1.453],[-0.001,1.636],[-2.621,1.341],[-4.909,0.563],[-8.182,-1.636]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,40.614],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[{"tm":210,"cm":"2","dr":0},{"tm":255,"cm":"1","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index b9875e5..c5578f2 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Beweeg na rand en versteek"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Beweeg weg van rand en wys"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"wissel"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Huiskontroles"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Toestelkontroles"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Kies program om kontroles by te voeg"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kontroles bygevoeg.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> het \'n boodskap gestuur: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> het \'n prent gestuur"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> het \'n statusopdatering: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Beskikbaar"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kon nie jou batterymeter lees nie"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tik vir meer inligting"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Geen wekker nie"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 2add74c..e64c7b4 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ወደ ጠርዝ አንቀሳቅስ እና ደደብቅ"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ጠርዙን ወደ ውጭ አንቀሳቅስ እና አሳይ"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ቀያይር"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"የቤት ውስጥ ቁጥጥሮች"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"የመሣሪያ መቆጣጠሪያዎች"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"መቆጣጠሪያዎችን ለማከል መተግበሪያ ይምረጡ"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> ቁጥጥሮች ታክለዋል።</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> መልዕክት ልከዋል፦ <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ምስል ልኳል"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> የሁኔታ ዝማኔ አለው፦ <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"የባትሪ መለኪያዎን የማንበብ ችግር"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ለበለጠ መረጃ መታ ያድርጉ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ምንም ማንቂያ አልተቀናበረም"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index c749f4d..5e1468c1 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -1064,7 +1064,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"نقله إلى الحافة وإخفاؤه"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"نقله إلى خارج الحافة وإظهاره"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"إيقاف/تفعيل"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"إدارة آلية للمنزل"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"أدوات التحكم بالأجهزة"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"اختيار تطبيق لإضافة عناصر التحكّم"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="zero">تمت إضافة <xliff:g id="NUMBER_1">%s</xliff:g> عنصر تحكّم.</item>
@@ -1170,10 +1170,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"عرض أحدث الرسائل والمكالمات الفائتة والتغييرات في الحالة"</string>
<string name="people_tile_title" msgid="6589377493334871272">"محادثة"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"تم إيقاف الإشعار مؤقتًا من خلال ميزة \"عدم الإزعاج\""</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"تم إرسال رسالة من <xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"تم إرسال صورة من <xliff:g id="NAME">%1$s</xliff:g>."</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"تم تعديل حالة <xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"حدثت مشكلة أثناء قراءة مقياس مستوى شحن البطارية."</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"انقر للحصول على مزيد من المعلومات."</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 6a99698..f870bae 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"কাষলৈ নিয়ক আৰু লুকুৱাওক"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"কাষৰ বাহিৰলৈ নিয়ক আৰু দেখুৱাওক"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ট’গল কৰক"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"গৃহ নিয়ন্ত্ৰণ"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহ"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"নিয়ন্ত্ৰণসমূহ যোগ কৰিবলৈ এপ্ বাছনি কৰক"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> টা নিয়ন্ত্ৰণ যোগ কৰা হ’ল।</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"শেহতীয়া বাৰ্তা, মিছড্ কল আৰু স্থিতিৰ আপডে’ট চাওক"</string>
<string name="people_tile_title" msgid="6589377493334871272">"বাৰ্তালাপ"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"অসুবিধা নিদিব সুবিধাটোৱে পজ কৰিছে"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>এ এটা বাৰ্তা পঠিয়াইছে: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>এ এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>ৰ এটা স্থিতিৰ আপডে’ট আছে: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"আপোনাৰ বেটাৰী মিটাৰ পঢ়োঁতে সমস্যা হৈছে"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"অধিক তথ্যৰ বাবে টিপক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 75375e8..1fdc227 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"İçəri keçirib gizlədin"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Kənara daşıyıb göstərin"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"keçirin"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Əsas səhifə nizamlayıcıları"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Cihaz kontrolları"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Kontrol əlavə etmək üçün tətbiq seçin"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> nizamlayıcı əlavə edilib.</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Son mesajlar, buraxılmış zənglər və status güncəlləmələrinə baxın"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Söhbət"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"\"Narahat Etməyin\" rejimini tərəfindən durdurulub"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> mesaj göndərdi: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> şəkil göndərdi"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> status güncəlləməsi edib: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batareya ölçüsünü oxuyarkən problem yarandı"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ətraflı məlumat üçün toxunun"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 6567e52..3c29f85 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -1049,7 +1049,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premesti do ivice i sakrij"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Premesti izvan ivice i prikaži"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"uključite/isključite"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Kontrole za dom"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Odaberite aplikaciju za dodavanje kontrola"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> kontrola je dodata.</item>
@@ -1155,6 +1155,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> je poslao/la poruku: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> šalje sliku"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ima ažuriranje statusa: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Dostupno"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem sa očitavanjem merača baterije"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarm nije podešen"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index e257f64..75c52bf 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -1054,7 +1054,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Перамясціць на край і схаваць"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Перамясціць за край і паказаць"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"уключыць/выключыць"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Элементы кіравання домам"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Элементы кіравання прыладай"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Выберыце праграму для дадавання элементаў кіравання"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one">Дададзены <xliff:g id="NUMBER_1">%s</xliff:g> элемент кіравання.</item>
@@ -1158,10 +1158,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Глядзець нядаўнія паведамленні, прапушчаныя выклікі і абнаўленні стану"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Размова"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"Прыпынена функцыяй \"Не турбаваць\""</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"Карыстальнік <xliff:g id="NAME">%1$s</xliff:g> прыслаў паведамленне: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"Карыстальнік <xliff:g id="NAME">%1$s</xliff:g> адправіў відарыс"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"Карыстальнік <xliff:g id="NAME">%1$s</xliff:g> абнавіў стан: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Праблема з чытаннем індыкатара зараду акумулятара"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Націсніце, каб убачыць больш"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 52ab96b..015504d 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Преместване в края и скриване"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Преместване в края и показване"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"превключване"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Контроли за дома"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Контроли за устройството"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Изберете приложение, за да добавите контроли"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">Добавени са <xliff:g id="NUMBER_1">%s</xliff:g> контроли.</item>
@@ -1146,11 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Преглеждайте скорошни съобщения, пропуснати обаждания и информация за състоянието"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Разговор"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"Поставено на пауза от режима „Не безпокойте“"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> изпрати съобщение: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> изпрати изображение"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
- <skip />
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> има актуализация на състоянието: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Налице"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Възникна проблем при четенето на данните за нивото на батерията"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Докоснете за още информация"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Няма зададен будилник"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 46bd79d..69f42e7 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -669,9 +669,8 @@
<string name="wallet_empty_state_label" msgid="7776761245237530394">"ফোন ব্যবহার করে আরও দ্রুত ও আরও নিরাপদে কেনাকাটা করার জন্য সেট-আপ করুন"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"সবকটি দেখুন"</string>
<string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"পেমেন্ট করতে ডিভাইস আনলক করুন"</string>
- <!-- no translation found for wallet_secondary_label_no_card (530725155985223497) -->
- <skip />
- <string name="wallet_secondary_label_updating" msgid="5726130686114928551">"আপডেট হচ্ছে"</string>
+ <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"কার্ড যোগ করুন"</string>
+ <string name="wallet_secondary_label_updating" msgid="5726130686114928551">"আপডেট করা হচ্ছে"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যবহার করতে আনলক করুন"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"আপনার কার্ড সংক্রান্ত তথ্য পেতে সমস্যা হয়েছে, পরে আবার চেষ্টা করুন"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"লক স্ক্রিন সেটিংস"</string>
@@ -1045,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"প্রান্তে যান ও আড়াল করুন"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"প্রান্ত থেকে সরান এবং দেখুন"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"টগল করুন"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"হোম কন্ট্রোল"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"ডিভাইস কন্ট্রোল"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"কন্ট্রোল যোগ করতে অ্যাপ বেছে নিন"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g>টি কন্ট্রোল যোগ করা হয়েছে।</item>
@@ -1147,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"সাম্প্রতিক মেসেজ, মিসড কল এবং স্ট্যাটাস সংক্রান্ত আপডেট দেখুন"</string>
<string name="people_tile_title" msgid="6589377493334871272">"কথোপকথন"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"\'বিরক্ত করবে না\' মোডের মাধ্যমে পজ করা আছে"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> একটি মেসেজ পাঠিয়েছেন: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> একটি ছবি পাঠিয়েছেন"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> একটি স্ট্যাটাস আপডেট করেছেন: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ব্যাটারির মিটারের রিডিং নেওয়ার সময় সমস্যা হয়েছে"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"আরও তথ্যের জন্য ট্যাপ করুন"</string>
@@ -1162,29 +1161,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"খুলতে ফিঙ্গারপ্রিন্ট ব্যবহার করুন"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"যাচাইকরণ করতে হবে। যাচাইকরণ করতে আঙুলের ছাপের সেন্সরে টাচ করুন।"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ব্যবহারকারী এখন ফোনে কথা বলছেন"</string>
- <!-- no translation found for airplane_mode (2536350001462130668) -->
- <skip />
- <!-- no translation found for mobile_data_settings_title (3955246641380064901) -->
- <skip />
- <!-- no translation found for preference_summary_default_combination (8453246369903749670) -->
- <skip />
+ <string name="airplane_mode" msgid="2536350001462130668">"বিমান মোড"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"মোবাইল ডেটা"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"কানেক্ট করা আছে"</string>
- <!-- no translation found for mobile_data_off_summary (5621158216585822679) -->
- <skip />
+ <string name="mobile_data_off_summary" msgid="5621158216585822679">"ইন্টারনেট অটোমেটিক কানেক্ট হবে না"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"কানেকশন নেই"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"অন্য কোনও নেটওয়ার্ক উপলভ্য নেই"</string>
<string name="all_network_unavailable" msgid="4112774339909373349">"কোনও নেটওয়ার্ক উপলভ্য নেই"</string>
- <!-- no translation found for turn_on_wifi (1308379840799281023) -->
- <skip />
- <!-- no translation found for pref_title_network_details (1639455355897668883) -->
- <!-- no translation found for pref_title_network_details (7329759534269363308) -->
- <skip />
- <!-- no translation found for tap_a_network_to_connect (1565073330852369558) -->
- <skip />
- <!-- no translation found for wifi_empty_list_wifi_on (3864376632067585377) -->
- <skip />
- <!-- no translation found for wifi_failed_connect_message (4161863112079000071) -->
- <skip />
- <!-- no translation found for see_all_networks (3773666844913168122) -->
- <skip />
+ <string name="turn_on_wifi" msgid="1308379840799281023">"ওয়াই-ফাই"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"নেটওয়ার্কের বিবরণ"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"কানেক্ট করতে একটি নেটওয়ার্কে ট্যাপ করুন"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"নেটওয়ার্ক সার্চ করা হচ্ছে…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"নেটওয়ার্কে কানেক্ট করা যায়নি"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"সবকটি দেখুন"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 3e8fa2a..20fc2c6 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -1049,7 +1049,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Pomjeranje do ivice i sakrivanje"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Pomjeranje izvan ivice i prikaz"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aktiviranje/deaktiviranje"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Kontrole doma"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Odaberite aplikaciju da dodate kontrole"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one">Dodana je <xliff:g id="NUMBER_1">%s</xliff:g> kontrola.</item>
@@ -1155,6 +1155,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> je poslao/la poruku: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> je poslao/la sliku"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> je ažurirao/la status: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Dostupan/na je"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Došlo je do problema prilikom očitavanja mjerača stanja baterije"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nije postavljen alarm"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 2903c21..2c95cd4 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mou dins de les vores i amaga"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mou fora de les vores i mostra"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"commuta"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Domòtica"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Controls de dispositius"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Selecciona l\'aplicació per afegir controls"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">S\'han afegit <xliff:g id="NUMBER_1">%s</xliff:g> controls.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ha enviat un missatge: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha enviat una imatge"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> té una actualització d\'estat: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Hi ha hagut un problema en llegir el mesurador de la bateria"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca per obtenir més informació"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Cap alarma configurada"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index cfcae92..b4937c6 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -1054,7 +1054,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Přesunout k okraji a skrýt"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Přesunout okraj ven a zobrazit"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"přepnout"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Ovládání domácnosti"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Ovládání zařízení"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Vyberte aplikaci, pro kterou chcete přidat ovládací prvky"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="few">Byly přidány <xliff:g id="NUMBER_1">%s</xliff:g> ovládací prvky.</item>
@@ -1158,11 +1158,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Zobrazit poslední zprávy, zmeškané hovory a aktualizace stavu"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Konverzace"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"Pozastaveno funkcí Nerušit"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> posílá zprávu: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> posílá obrázek"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
- <skip />
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> má aktualizaci stavu: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Dostupné"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problém s načtením měřiče baterie"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Klepnutím zobrazíte další informace"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Budík nenastaven"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 6bbdb70..28912a7 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flyt ud til kanten, og skjul"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flyt ud til kanten, og vis"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"slå til/fra"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Styring af smartenheder"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Enhedsstyring"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Vælg en app for at tilføje styring"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> styring er tilføjet.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> har sendt en besked: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> har sendt et billede"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> har opdateret sin status: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Der er problemer med at aflæse dit batteriniveau"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tryk for at få flere oplysninger"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ingen alarm er indstillet"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 8b9d19e..5b31275 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"An den Rand verschieben und verbergen"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Vom Rand verschieben und anzeigen"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"Wechseln"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Smart-Home-Steuerung"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Gerätesteuerung"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"App zum Hinzufügen von Steuerelementen auswählen"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> Steuerelemente hinzugefügt.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> hat eine Nachricht gesendet: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> hat ein Bild gesendet"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> hat den Status aktualisiert: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Verfügbar"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem beim Lesen des Akkustands"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Für weitere Informationen tippen"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Kein Wecker gestellt"</string>
@@ -1159,29 +1160,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Mit Fingerabdruck öffnen"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentifizierung erforderlich. Tippe dazu einfach auf den Fingerabdrucksensor."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Aktiver Anruf"</string>
- <!-- no translation found for airplane_mode (2536350001462130668) -->
- <skip />
- <!-- no translation found for mobile_data_settings_title (3955246641380064901) -->
- <skip />
- <!-- no translation found for preference_summary_default_combination (8453246369903749670) -->
- <skip />
+ <string name="airplane_mode" msgid="2536350001462130668">"Flugmodus"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile Daten"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Verbunden"</string>
- <!-- no translation found for mobile_data_off_summary (5621158216585822679) -->
- <skip />
+ <string name="mobile_data_off_summary" msgid="5621158216585822679">"Keine automatische Verbindung mit dem Internet"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Keine Verbindung"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Keine anderen Netzwerke verfügbar"</string>
<string name="all_network_unavailable" msgid="4112774339909373349">"Keine Netzwerke verfügbar"</string>
- <!-- no translation found for turn_on_wifi (1308379840799281023) -->
- <skip />
- <!-- no translation found for pref_title_network_details (1639455355897668883) -->
- <!-- no translation found for pref_title_network_details (7329759534269363308) -->
- <skip />
- <!-- no translation found for tap_a_network_to_connect (1565073330852369558) -->
- <skip />
- <!-- no translation found for wifi_empty_list_wifi_on (3864376632067585377) -->
- <skip />
- <!-- no translation found for wifi_failed_connect_message (4161863112079000071) -->
- <skip />
- <!-- no translation found for see_all_networks (3773666844913168122) -->
- <skip />
+ <string name="turn_on_wifi" msgid="1308379840799281023">"WLAN"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Netzwerkdetails"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tippe auf ein Netzwerk, um eine Verbindung herzustellen"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Netzwerke werden gesucht…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Netzwerkverbindung konnte nicht hergestellt werden"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Alle ansehen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 3a8dea7..de23a88 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Μετακίν. στο άκρο και απόκρυψη"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Μετακ. εκτός άκρου και εμφάν."</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"εναλλαγή"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Οικιακοί έλεγχοι"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Στοιχεία ελέγχου συσκευής"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Επιλογή εφαρμογής για προσθήκη στοιχείων ελέγχου"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">Προστέθηκαν <xliff:g id="NUMBER_1">%s</xliff:g> στοιχεία ελέγχου.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> έστειλε ένα μήνυμα: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> έστειλε μια εικόνα"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> έχει μια ενημέρωση κατάστασης: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Υπάρχει κάποιο πρόβλημα με την ανάγνωση του μετρητή μπαταρίας"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Πατήστε για περισσότερες πληροφορίες."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Δεν ορίστηκε ξυπνητ."</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 88864a3..38630e1 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Home controls"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controls added.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sent a message: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sent an image"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> has a status update: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Available"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index a5246f3..0669461 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Home controls"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controls added.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sent a message: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sent an image"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> has a status update: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Available"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 88864a3..38630e1 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Home controls"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controls added.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sent a message: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sent an image"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> has a status update: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Available"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 88864a3..38630e1 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Home controls"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controls added.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sent a message: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sent an image"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> has a status update: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Available"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 928976d..5668317 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Home controls"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controls added.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sent a message: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sent an image"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> has a status update: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Available"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index c50eaea..fd66af0 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover fuera de borde y ocultar"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover fuera de borde y mostrar"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar o desactivar"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Controles de la casa"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Controles de dispositivos"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Elige la app para agregar los controles"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">Se agregaron <xliff:g id="NUMBER_1">%s</xliff:g> controles.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> envió un mensaje: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> envió una imagen"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> actualizó su estado: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema al leer el medidor de batería"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Presiona para obtener más información"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No se estableció alarma"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 264a297..c02f80f 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover al borde y ocultar"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover al borde y mostrar"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar/desactivar"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Domótica"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Elige una aplicación para añadir controles"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">Se han añadido <xliff:g id="NUMBER_1">%s</xliff:g> controles.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ha enviado un mensaje: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha enviado una imagen"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ha cambiado su estado: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Disponible"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"No se ha podido leer el indicador de batería"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca la pantalla para consultar más información"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ninguna alarma puesta"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 89018b3..b23b283 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Teisalda serva ja kuva"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Teisalda servast eemale ja kuva"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"lülita"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Kodu juhtelemendid"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Seadmete juhikud"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Valige juhtelementide lisamiseks rakendus"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">Lisati <xliff:g id="NUMBER_1">%s</xliff:g> juhtnuppu.</item>
@@ -1146,11 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Vaadake hiljutisi sõnumeid, vastamata kõnesid ja olekuvärskendusi"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Vestlus"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"Peatas režiim Mitte segada"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> saatis sõnumi: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> saatis pildi"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
- <skip />
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> värskendas olekut: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Saadaval"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probleem akumõõdiku lugemisel"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Puudutage lisateabe saamiseks"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Äratust pole"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 79b00db..6344f62 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Eraman ertzera eta ezkutatu"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Atera ertzetik eta erakutsi"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aldatu"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Etxeko gailuak kontrolatzeko aukerak"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Gailuak kontrolatzeko widgetak"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Aukeratu aplikazio bat kontrolatzeko aukerak gehitzeko"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kontrol-aukera gehitu dira.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak mezu bat bidali du: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak irudi bat bidali du"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak egoera eguneratu du: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Konektatuta"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Arazo bat gertatu da bateria-neurgailua irakurtzean"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Informazio gehiago lortzeko, sakatu hau"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ez da ezarri alarmarik"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 151c70a..6988df2 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"انتقال به لبه و پنهان کردن"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"انتقال به خارج از لبه و نمایش"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"روشن/ خاموش کردن"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"کنترلهای لوازم خانگی"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"کنترلهای دستگاه"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"انتخاب برنامه برای افزودن کنترلها"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> کنترل اضافه شده است.</item>
@@ -1146,11 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"دیدن بهروزرسانیهای وضعیت، تماسهای بیپاسخ، و پیامهای اخیر"</string>
<string name="people_tile_title" msgid="6589377493334871272">"مکالمه"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"با «مزاحم نشوید» موقتاً متوقف شده است"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> پیامی ارسال کرد: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> تصویری ارسال کرد"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
- <skip />
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> وضعیتش را بهروزرسانی کرد: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"دردسترس"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"مشکلی در خواندن میزان باتری وجود دارد"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"برای اطلاعات بیشتر ضربه بزنید"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"هشداری تنظیم نشده است"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 4959e5b..0e7894a 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Siirrä reunaan ja piilota"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Siirrä pois reunasta ja näytä"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"vaihda"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Kodin ohjaus"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Laitteiden hallinta"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Valitse sovellus lisätäksesi säätimiä"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> säädintä lisätty</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> lähetti viestin: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> lähetti kuvan"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> on päivittänyt tilansa: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Ongelma akkumittarin lukemisessa"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Saat lisätietoja napauttamalla"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ei herätyksiä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index bc6c4fc..decba94 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -420,9 +420,9 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Jusqu\'à l\'aube"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Actif à <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Jusqu\'à <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
- <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC désactivée"</string>
- <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC activée"</string>
+ <string name="quick_settings_nfc_label" msgid="1054317416221168085">"CCP"</string>
+ <string name="quick_settings_nfc_off" msgid="3465000058515424663">"CCP désactivée"</string>
+ <string name="quick_settings_nfc_on" msgid="1004976611203202230">"CCP activée"</string>
<string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Enregistrement de l\'écran"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Démarrer"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Arrêter"</string>
@@ -455,7 +455,7 @@
<string name="tap_again" msgid="1315420114387908655">"Toucher de nouveau"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Balayez l\'écran vers le haut pour ouvrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Balayez l\'écran vers le haut pour réessayer"</string>
- <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour utiliser la NFC"</string>
+ <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour utiliser la CCP"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Cet appareil appartient à <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Cet appareil est fourni par <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Éloigner du bord et masquer"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Éloigner du bord et afficher"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"basculer"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Domotique"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'application pour laquelle ajouter des commandes"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> commande ajoutée.</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Affichez les messages récents, les appels manqués et les mises à jour d\'état"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversation"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"Interrompue par la fonctionnalité Ne pas déranger"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé un message : <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé une image"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> a mis à jour son état : <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Un problème est survenu lors de la lecture du niveau de charge de la pile"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Touchez pour en savoir plus"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 7033449..267f88e 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Rapprocher du bord et masquer"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Éloigner du bord et afficher"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activer/désactiver"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Commandes de la maison"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'appli pour laquelle ajouter des commandes"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> commande ajoutée.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé un message : <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé une image"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> a mis à jour son statut : <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Un problème est survenu au niveau de la lecture de votre outil de mesure de batterie"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Appuyer pour en savoir plus"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Pas d\'alarme définie"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index ca96bf4..703f1029 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover ao bordo e ocultar"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover fóra do bordo e mostrar"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar/desactivar"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Controis domóticos"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolle unha aplicación para engadir controis"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">Engadíronse <xliff:g id="NUMBER_1">%s</xliff:g> controis.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> enviou unha mensaxe: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou unha imaxe"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> cambiou de estado: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Produciuse un problema ao ler o medidor da batería"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca para obter máis información"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Sen alarmas postas"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 278efa3..fa078b6 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -669,8 +669,7 @@
<string name="wallet_empty_state_label" msgid="7776761245237530394">"તમારા ફોન વડે વધુ ઝડપી તેમજ સુરક્ષિત ખરીદીઓ કરવાની રીત સેટઅપ કરી લો"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"બધું બતાવો"</string>
<string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"ચુકવણી કરવા માટે અનલૉક કરો"</string>
- <!-- no translation found for wallet_secondary_label_no_card (530725155985223497) -->
- <skip />
+ <string name="wallet_secondary_label_no_card" msgid="530725155985223497">"કોઈ કાર્ડ ઉમેરો"</string>
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"અપડેટ કરી રહ્યાં છીએ"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ઉપયોગ કરવા માટે અનલૉક કરો"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"તમારા કાર્ડની માહિતી મેળવવામાં સમસ્યા આવી હતી, કૃપા કરીને થોડા સમય પછી ફરી પ્રયાસ કરો"</string>
@@ -1045,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"કિનારી પર ખસેડો અને છુપાવો"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"કિનારીથી ખસેડો અને બતાવો"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ટૉગલ કરો"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"ઘરેલું સાધનોનાં નિયંત્રણો"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"ડિવાઇસનાં નિયંત્રણો"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"નિયંત્રણો ઉમેરવા માટે ઍપ પસંદ કરો"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> નિયંત્રણ ઉમેર્યું.</item>
@@ -1147,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"તાજેતરના સંદેશા, ચૂકી ગયેલા કૉલ અને સ્ટેટસ અપડેટ જુઓ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"વાતચીત"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"\'ખલેલ પાડશો નહીં\'ની સુવિધા દ્વારા થોભાવેલું"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કોઈ સંદેશ મોકલવામાં આવ્યો: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કોઈ છબી મોકલવામાં આવી"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા નવી સ્ટેટસ અપડેટ પોસ્ટ કરવામાં આવી: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"તમારું બૅટરી મીટર વાંચવામાં સમસ્યા આવી"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"વધુ માહિતી માટે ટૅપ કરો"</string>
@@ -1162,29 +1161,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ખોલવા માટે ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"પ્રમાણીકરણ આવશ્યક છે. પ્રમાણિત કરવા માટે ફિંગરપ્રિન્ટ સેન્સરને ટચ કરો."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ફોન કૉલ ચાલુ છે"</string>
- <!-- no translation found for airplane_mode (2536350001462130668) -->
- <skip />
- <!-- no translation found for mobile_data_settings_title (3955246641380064901) -->
- <skip />
- <!-- no translation found for preference_summary_default_combination (8453246369903749670) -->
- <skip />
+ <string name="airplane_mode" msgid="2536350001462130668">"એરપ્લેન મોડ"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"મોબાઇલ ડેટા"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"કનેક્ટ કરેલું"</string>
- <!-- no translation found for mobile_data_off_summary (5621158216585822679) -->
- <skip />
+ <string name="mobile_data_off_summary" msgid="5621158216585822679">"ઇન્ટરનેટ ઑટોમૅટિક રીતે કનેક્ટ થશે નહીં"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"કોઈ કનેક્શન નથી"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"બીજાં કોઈ નેટવર્ક ઉપલબ્ધ નથી"</string>
<string name="all_network_unavailable" msgid="4112774339909373349">"કોઈ નેટવર્ક ઉપલબ્ધ નથી"</string>
- <!-- no translation found for turn_on_wifi (1308379840799281023) -->
- <skip />
- <!-- no translation found for pref_title_network_details (1639455355897668883) -->
- <!-- no translation found for pref_title_network_details (7329759534269363308) -->
- <skip />
- <!-- no translation found for tap_a_network_to_connect (1565073330852369558) -->
- <skip />
- <!-- no translation found for wifi_empty_list_wifi_on (3864376632067585377) -->
- <skip />
- <!-- no translation found for wifi_failed_connect_message (4161863112079000071) -->
- <skip />
- <!-- no translation found for see_all_networks (3773666844913168122) -->
- <skip />
+ <string name="turn_on_wifi" msgid="1308379840799281023">"વાઇ-ફાઇ"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"નેટવર્કની વિગતો"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"કનેક્ટ કરવા માટે નેટવર્ક પર ટૅપ કરો"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"નેટવર્ક શોધી રહ્યાં છીએ…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"નેટવર્ક સાથે કનેક્ટ કરવામાં નિષ્ફળ થયાં"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"બધા જુઓ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index b8764bf..761ad05 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"एज पर ले जाएं और छिपाएं"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"एज से निकालें और दिखाएं"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"टॉगल करें"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"होम कंट्रोल"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"डिवाइस कंट्रोल"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"कंट्रोल जोड़ने के लिए ऐप्लिकेशन चुनें"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> कंट्रोल जोड़ा गया.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ने एक मैसेज भेजा है: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ने एक इमेज भेजी है"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ने स्टेटस अपडेट किया है: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"ऑनलाइन हैं"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"आपके डिवाइस के बैटरी मीटर की रीडिंग लेने में समस्या आ रही है"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ज़्यादा जानकारी के लिए टैप करें"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"कोई अलार्म सेट नहीं है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 2daf868..bbba1a8 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -1049,7 +1049,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premjesti na rub i sakrij"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Ukloni s ruba i prikaži"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"promijeni"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Upravljanje kuć. uređajima"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Odabir aplikacije za dodavanje kontrola"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one">Dodana je <xliff:g id="NUMBER_1">%s</xliff:g> kontrola.</item>
@@ -1155,6 +1155,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> šalje poruku: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"Korisnik <xliff:g id="NAME">%1$s</xliff:g> poslao je sliku"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ima ažuriranje statusa: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Dostupan/dostupna"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem s očitavanjem mjerača baterije"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nema nijednog alarma"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 90684c6..78a8aee 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Áthelyezés a szélen kívül és elrejtés"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Áthelyezés a szélen kívül és mutatás"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"váltás"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Otthon vezérlése"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Eszközvezérlők"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Válasszon alkalmazást a vezérlők hozzáadásához"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> vezérlő hozzáadva.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> üzenetet küldött: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> képet küldött"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> frissítette állapotát: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probléma merült fel az akkumulátor-töltésmérő olvasásakor"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Koppintással további információkat érhet el."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nincs ébresztés"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 27f8bec..95b2d6a 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Տեղափոխել եզրից դուրս և թաքցնել"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Տեղափոխել եզրից դուրս և ցուցադրել"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"միացնել/անջատել"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Խելացի տուն"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Սարքերի կառավարման տարրեր"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Ընտրեք հավելված` կառավարման տարրեր ավելացնելու համար"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one">Ավելացվեց կառավարման <xliff:g id="NUMBER_1">%s</xliff:g> տարր։</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը հաղորդագրություն է ուղարկել. «<xliff:g id="NOTIFICATION">%2$s</xliff:g>»"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը պատկեր է ուղարկել"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը նոր կարգավիճակ է հրապարակել. «<xliff:g id="STATUS">%2$s</xliff:g>»"</string>
+ <string name="person_available" msgid="2318599327472755472">"Հասանելի է"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Մարտկոցի ցուցիչի ցուցմունքը կարդալու հետ կապված խնդիր կա"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Հպեք՝ ավելին իմանալու համար"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Զարթուցիչ դրված չէ"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 2755cf1..2af2f24 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Pindahkan ke tepi dan sembunyikan"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Pindahkan dari tepi dan tampilkan"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alihkan"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Kontrol rumah"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Kontrol perangkat"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Pilih aplikasi untuk menambahkan kontrol"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kontrol ditambahkan.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> mengirim pesan: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> mengirim gambar"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> memposting pembaruan status: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Terjadi masalah saat membaca indikator baterai"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ketuk untuk informasi selengkapnya"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarm tidak disetel"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 9408d6d..dff08d1 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Færa að jaðri og fela"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Færa að jaðri og birta"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"kveikja/slökkva"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Heimastýringar"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Tækjastjórnun"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Veldu forrit til að bæta við stýringum"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> stýringu bætt við.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sendi skilaboð: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sendi mynd"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> er með stöðuuppfærslu: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Vandamál við að lesa stöðu rafhlöðu"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ýttu til að fá frekari upplýsingar"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Enginn vekjari"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index b53c139..6f160b9 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Sposta fino a bordo e nascondi"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Sposta fuori da bordo e mostra"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"attiva/disattiva"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Controlli della casa"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Controllo dei dispositivi"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Scegli un\'app per aggiungere controlli"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controlli aggiunti.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ha inviato un messaggio: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha inviato un\'immagine"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ha aggiornato lo stato: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Disponibile"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema durante la lettura dell\'indicatore di livello della batteria"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tocca per ulteriori informazioni"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nessuna sveglia"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index ad1a8e3..73e1a74 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -1054,7 +1054,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"העברה לשוליים והסתרה"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"העברה מהשוליים והצגה"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"החלפת מצב"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"פקדי הבית החכם"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"פקדי מכשירים"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"יש לבחור אפליקציה כדי להוסיף פקדים"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="two">נוספו <xliff:g id="NUMBER_1">%s</xliff:g> פקדים.</item>
@@ -1158,10 +1158,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"ההודעות האחרונות, שיחות שלא נענו ועדכוני סטטוס"</string>
<string name="people_tile_title" msgid="6589377493334871272">"שיחה"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"ההתראה הושהתה על ידי \'נא לא להפריע\'"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"התקבלה הודעה מ<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> שלח/ה תמונה"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"הסטטוס של <xliff:g id="NAME">%1$s</xliff:g> עודכן: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"בעיה בקריאת מדדי הסוללה"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"יש להקיש כדי להציג מידע נוסף"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 2b83e3d..1e8020f 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"端に移動して非表示"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"端から移動して表示"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"切り替え"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"ホーム コントロール"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"デバイス コントロール"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"コントロールを追加するアプリの選択"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> 件のコントロールを追加しました。</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> さんからのメッセージ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> さんが画像を送信しました"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> さんの近況: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"オンライン"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"バッテリー残量の読み込み中に問題が発生しました"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"タップすると詳細が表示されます"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"アラーム未設定"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 93b3f65..b35decc 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"კიდეში გადატანა და დამალვა"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"კიდეში გადატანა და გამოჩენა"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"გადართვა"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"სახლის მართვის საშუალებები"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"მოწყობილ. მართვის საშუალებები"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"აირჩიეთ აპი მართვის საშუალებების დასამატებლად"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">დაემატა <xliff:g id="NUMBER_1">%s</xliff:g> მართვის საშუალება.</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"ბოლოდროინდელი შეტყობინებების, გამოტოვებული ზარების და სტატუსის განახლებების ნახვა"</string>
<string name="people_tile_title" msgid="6589377493334871272">"მიმოწერა"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"დაპაუზებულია ფუნქციის „არ შემაწუხოთ“ მიერ"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>-მა გაგზავნა შეტყობინება: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>-მ(ა) სურათი გამოგზავნა"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>-მა განაახლა სტატუსი: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"თქვენი ბატარეის მზომის წაკითხვასთან დაკავშირებით პრობლემა დაფიქსირდა"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"შეეხეთ მეტი ინფორმაციისთვის"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 8b4c8e3..e192c98 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Шетке жылжыту және жасыру"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Шетке жылжыту және көрсету"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ауыстыру"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Үйді басқару элементтері"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Құрылғыны басқару элементтері"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Басқару элементтері қосылатын қолданбаны таңдаңыз"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> басқару элементі енгізілді.</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Соңғы хабарларды, өткізіп алған қоңыраулар мен жаңартылған күйлерді көруге болады."</string>
<string name="people_tile_title" msgid="6589377493334871272">"Әңгіме"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"Мазаламау режимі арқылы кідіртілді."</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> хабар жіберді: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> сурет жіберді."</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ағымдағы күйін жаңартты: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Батарея зарядының дерегі алынбай жатыр"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Толығырақ ақпарат алу үшін түртіңіз."</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index faa9e75..183712b 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ផ្លាស់ទីទៅផ្នែកខាងចុង រួចលាក់"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ផ្លាស់ទីចេញពីផ្នែកខាងចុង រួចបង្ហាញ"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"បិទ/បើក"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"ការគ្រប់គ្រងផ្ទះ"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"ផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ជ្រើសរើសកម្មវិធីដែលត្រូវបញ្ចូលផ្ទាំងគ្រប់គ្រង"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">បានបញ្ចូលការគ្រប់គ្រង <xliff:g id="NUMBER_1">%s</xliff:g>។</item>
@@ -1146,11 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"មើលព័ត៌មានថ្មីៗអំពីស្ថានភាព ការខកខានទទួល និងសារថ្មីៗ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"ការសន្ទនា"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"បានផ្អាកដោយមុខងារកុំរំខាន"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> បានផ្ញើសារ៖ <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> បានផ្ញើរូបភាព"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
- <skip />
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> មានបច្ចុប្បន្នភាពស្ថានភាព៖ <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"មាន"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"មានបញ្ហាក្នុងការអានឧបករណ៍រង្វាស់កម្រិតថ្មរបស់អ្នក"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ចុចដើម្បីទទួលបានព័ត៌មានបន្ថែម"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"មិនបានកំណត់ម៉ោងរោទ៍ទេ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 578a503..8eb874d 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ಅಂಚಿಗೆ ಸರಿಸಿ ಮತ್ತು ಮರೆಮಾಡಿ"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ಅಂಚನ್ನು ಸರಿಸಿ ಮತ್ತು ತೋರಿಸಿ"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ಟಾಗಲ್ ಮಾಡಿ"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"ಹೋಮ್ ನಿಯಂತ್ರಣಗಳು"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"ಸಾಧನ ನಿಯಂತ್ರಣಗಳು"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲಾಗಿದೆ.</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"ಇತ್ತೀಚಿನ ಸಂದೇಶಗಳು, ಮಿಸ್ಡ್ ಕಾಲ್ಗಳು ಮತ್ತು ಸ್ಥಿತಿ ಅಪ್ಡೇಟ್ಗಳು"</string>
<string name="people_tile_title" msgid="6589377493334871272">"ಸಂಭಾಷಣೆ"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"\'ಅಡಚಣೆ ಮಾಡಬೇಡಿ\' ನಿಂದ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಸಂದೇಶವನ್ನು ಕಳುಹಿಸಿದ್ದಾರೆ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಿದ್ದಾರೆ"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಸ್ಥಿತಿಯ ಅಪ್ಡೇಟ್ ಹೊಂದಿದ್ದಾರೆ: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ನಿಮ್ಮ ಬ್ಯಾಟರಿ ಮೀಟರ್ ಓದುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -1161,29 +1161,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ತೆರೆಯುವುದಕ್ಕಾಗಿ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಬಳಸಿ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ದೃಢೀಕರಣದ ಅವಶ್ಯಕತೆಯಿದೆ. ದೃಢೀಕರಿಸಲು ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಫೋನ್ ಕರೆ"</string>
- <!-- no translation found for airplane_mode (2536350001462130668) -->
- <skip />
- <!-- no translation found for mobile_data_settings_title (3955246641380064901) -->
- <skip />
- <!-- no translation found for preference_summary_default_combination (8453246369903749670) -->
- <skip />
+ <string name="airplane_mode" msgid="2536350001462130668">"ಏರ್ಪ್ಲೇನ್ ಮೋಡ್"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"ಮೊಬೈಲ್ ಡೇಟಾ"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
- <!-- no translation found for mobile_data_off_summary (5621158216585822679) -->
- <skip />
+ <string name="mobile_data_off_summary" msgid="5621158216585822679">"ಇಂಟರ್ನೆಟ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಕನೆಕ್ಟ್ ಆಗುವುದಿಲ್ಲ"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"ಯಾವುದೇ ಕನೆಕ್ಷನ್ ಇಲ್ಲ"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"ಇತರ ಯಾವುದೇ ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="all_network_unavailable" msgid="4112774339909373349">"ಯಾವುದೇ ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
- <!-- no translation found for turn_on_wifi (1308379840799281023) -->
- <skip />
- <!-- no translation found for pref_title_network_details (1639455355897668883) -->
- <!-- no translation found for pref_title_network_details (7329759534269363308) -->
- <skip />
- <!-- no translation found for tap_a_network_to_connect (1565073330852369558) -->
- <skip />
- <!-- no translation found for wifi_empty_list_wifi_on (3864376632067585377) -->
- <skip />
- <!-- no translation found for wifi_failed_connect_message (4161863112079000071) -->
- <skip />
- <!-- no translation found for see_all_networks (3773666844913168122) -->
- <skip />
+ <string name="turn_on_wifi" msgid="1308379840799281023">"ವೈ‑ಫೈ"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"ನೆಟ್ವರ್ಕ್ ವಿವರಗಳು"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ಕನೆಕ್ಟ್ ಮಾಡಲು ಒಂದು ನೆಟ್ವರ್ಕ್ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ನೆಟ್ವರ್ಕ್ಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ನೆಟ್ವರ್ಕ್ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"ಎಲ್ಲವನ್ನೂ ನೋಡಿ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 0691c7a..f1cd190 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -1034,9 +1034,9 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"전체 화면 확대"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"화면 일부 확대"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"전환"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"접근성 동작이 접근성 버튼으로 대체되었습니다\n\n"<annotation id="link">"설정 보기"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"접근성 동작이 접근성 버튼으로 대체되었습니다.\n\n"<annotation id="link">"설정 보기"</annotation></string>
<string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"접근성 동작을 버튼으로 전환할 수 있습니다.\n\n"<annotation id="link">"설정"</annotation></string>
- <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"버튼을 가장자리로 옮겨서 일시적으로 숨기세요"</string>
+ <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"버튼을 가장자리로 옮겨서 일시적으로 숨기세요."</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"왼쪽 상단으로 이동"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"오른쪽 상단으로 이동"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"왼쪽 하단으로 이동"</string>
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"가장자리로 옮겨서 숨기기"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"가장자리 바깥으로 옮겨서 표시"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"전환"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"홈 컨트롤"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"기기 컨트롤"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"컨트롤을 추가할 앱을 선택하세요"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">제어 기능 <xliff:g id="NUMBER_1">%s</xliff:g>개가 추가되었습니다.</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"최근 메시지, 부재중 전화, 상태 업데이트 보기"</string>
<string name="people_tile_title" msgid="6589377493334871272">"대화"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"방해 금지 모드로 인해 일시중지됨"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>님이 메시지를 보냈습니다: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>님이 이미지를 보냈습니다."</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>님의 상태가 업데이트되었습니다: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"배터리 수준을 읽는 중에 문제가 발생함"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"탭하여 자세한 정보를 확인하세요."</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 1fd71ad..c0fce99 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Ичине жылдырып, көрсөтүңүз"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Сыртка жылдырып, көрсөтүңүз"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"өчүрүү/күйгүзүү"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Үйдү башкаруу элементтери"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Түзмөктү башкаруу элементтери"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Башкаруу элементтери кошула турган колдонмону тандоо"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> башкаруу элементи кошулду.</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Акыркы билдирүүлөрдү, жооп берилбеген чалууларды жана статустардын жаңырганын көрөсүз"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Сүйлөшүү"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"\"Тынчымды алба\" режими тындырды"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> билдирүү жөнөттү: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> сүрөт жөнөттү"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> жаңы абалы тууралуу жарыялады: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Батареяңыздын кубаты аныкталбай жатат"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Кеңири маалымат алуу үчүн таптап коюңуз"</string>
diff --git a/packages/SystemUI/res/values-land-television/dimens.xml b/packages/SystemUI/res/values-land-television/dimens.xml
index a9bc9e5..8fc4612 100644
--- a/packages/SystemUI/res/values-land-television/dimens.xml
+++ b/packages/SystemUI/res/values-land-television/dimens.xml
@@ -22,7 +22,7 @@
<dimen name="volume_dialog_panel_transparent_padding">24dp</dimen>
<dimen name="volume_dialog_slider_width">4dp</dimen>
<dimen name="volume_dialog_slider_corner_radius">@dimen/volume_dialog_slider_width</dimen>
- <dimen name="volume_dialog_background_blur_radius">100dp</dimen>
+ <dimen name="volume_dialog_background_blur_radius">31dp</dimen>
<dimen name="volume_tool_tip_right_margin">136dp</dimen>
<dimen name="tv_volume_dialog_bubble_size">36dp</dimen>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index be4424b..3c136b9 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ຍ້າຍອອກຂອບ ແລະ ເຊື່ອງ"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ຍ້າຍອອກຂອບ ແລະ ສະແດງ"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ສະຫຼັບ"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"ການຄວບຄຸມເຮືອນ"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"ການຄວບຄຸມອຸປະກອນ"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ເລືອກແອັບເພື່ອເພີ່ມການຄວບຄຸມ"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">ເພີ່ມ <xliff:g id="NUMBER_1">%s</xliff:g> ການຄວບຄຸມແລ້ວ.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ສົ່ງຂໍ້ຄວາມ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ສົ່ງຮູບພາບແລ້ວ"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ອັບເດດສະຖານະ: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ເກີດບັນຫາໃນການອ່ານຕົວວັດແທກແບັດເຕີຣີຂອງທ່ານ"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ບໍ່ໄດ້ຕັ້ງໂມງປຸກ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index e8f6d06..39865f1 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -1054,7 +1054,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Perkelti į kraštą ir slėpti"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Perkelti iš krašto ir rodyti"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"perjungti"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Namų sistemos valdikliai"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Įrenginio valdikliai"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Pasirinkite programą, kad pridėtumėte valdiklių"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one">Pridėtas <xliff:g id="NUMBER_1">%s</xliff:g> valdiklis.</item>
@@ -1161,6 +1161,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> išsiuntė pranešimą: „<xliff:g id="NOTIFICATION">%2$s</xliff:g>“"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> išsiuntė vaizdą"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> atnaujino būseną: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nuskaitant akumuliatoriaus skaitiklį iškilo problema"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Palieskite, kad sužinotumėte daugiau informacijos"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nenustatyta signalų"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index e51847a..860d338 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -1049,7 +1049,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Pārvietot uz malu un paslēpt"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Pārvietot no malas un parādīt"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"pārslēgt"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Mājas kontrolierīces"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Ierīču vadīklas"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Izvēlieties lietotni, lai pievienotu vadīklas"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="zero">Pievienotas <xliff:g id="NUMBER_1">%s</xliff:g> vadīklas.</item>
@@ -1155,6 +1155,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> nosūtīja ziņojumu: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> nosūtīja attēlu"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> atjaunināja statusu: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nevar iegūt informāciju par akumulatora uzlādes līmeni."</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Pieskarieties, lai iegūtu plašāku informāciju."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nav iestatīts signāls"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index cc51acb..db02f9a 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Премести до работ и сокриј"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Премести над работ и прикажи"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"вклучување/исклучување"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Контроли за домот"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Контроли за уредите"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Изберете апликација за да додадете контроли"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one">Додадена е <xliff:g id="NUMBER_1">%s</xliff:g> контрола.</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Видете ги неодамнешните пораки, пропуштени повици и промени на статусот"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Разговор"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"Паузирано од „Не вознемирувај“"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> испрати порака: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> испрати слика"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> има ажурирање на статусот: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Проблем при читањето на мерачот на батеријата"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Допрете за повеќе информации"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 1c9c162..1c3837f 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"എഡ്ജിലേക്ക് നീക്കി മറയ്ക്കുക"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"എഡ്ജിൽ നിന്ന് നീക്കി കാണിക്കൂ"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"മാറ്റുക"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"ഹോം കൺട്രോളുകൾ"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"ഉപകരണ നിയന്ത്രണങ്ങൾ"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"നിയന്ത്രണങ്ങൾ ചേർക്കാൻ ആപ്പ് തിരഞ്ഞെടുക്കുക"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> നിയന്ത്രണങ്ങൾ ചേർത്തു.</item>
@@ -1146,11 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"അടുത്തിടെയുള്ള സന്ദേശങ്ങൾ, മിസ്ഡ് കോൾ, സ്റ്റാറ്റസ് അപ്ഡേറ്റുകൾ എന്നിവ കാണൂ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"സംഭാഷണം"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"\'ശല്യപ്പെടുത്തരുത്\' ഓണായതിനാൽ തൽക്കാലം നിർത്തി"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ഒരു സന്ദേശം അയച്ചു: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>, ഒരു ചിത്രം അയച്ചു"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
- <skip />
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> എന്നയാൾ സ്റ്റാറ്റസ് അപ്ഡേറ്റ് ചെയ്തു: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"ലഭ്യമാണ്"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"നിങ്ങളുടെ ബാറ്ററി മീറ്റർ വായിക്കുന്നതിൽ പ്രശ്നമുണ്ട്"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"കൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"അലാറം സജ്ജീകരിച്ചിട്ടില്ല"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index ed7ca55..4e04c61 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Ирмэг рүү зөөж, нуух"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Ирмэгээс гаргаж, харуулах"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"асаах/унтраах"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Гэрийн удирдлагууд"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Төхөөрөмжийн хяналт"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Хяналтууд нэмэхийн тулд аппыг сонгоно уу"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> хяналтыг нэмлээ.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> мессеж илгээсэн: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> зураг илгээсэн"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> төлөвийн шинэчлэлт хийсэн байна: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Боломжтой"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Таны батарей хэмжигчийг уншихад асуудал гарлаа"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Нэмэлт мэдээлэл авахын тулд товшино уу"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Сэрүүлэг тавиагүй"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index addccf2..b8dfaeb 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"एजवर हलवा आणि लपवा"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"एजवर हलवा आणि दाखवा"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"टॉगल करा"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"होम कंट्रोल"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"डिव्हाइस नियंत्रणे"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"नियंत्रणे जोडण्यासाठी ॲप निवडा"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> नियंत्रणे जोडली.</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"अलीकडील मेसेज, मिस्ड कॉल आणि स्टेटस अपडेट पाहा"</string>
<string name="people_tile_title" msgid="6589377493334871272">"संभाषण"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"व्यत्यय आणू नका द्वारे थांबवले गेले"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> यांनी मेसेज पाठवला: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> यांनी इमेज पाठवली"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> यांनी स्टेटस अपडेट केले: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"तुमचे बॅटरी मीटर वाचताना समस्या आली"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"अधिक माहितीसाठी टॅप करा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 36fbee9..72baf12 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Alihkan ke tepi dan sorokkan"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Alihkan ke tepi dan tunjukkan"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"togol"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Kawalan rumah"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Kawalan peranti"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Pilih apl untuk menambahkan kawalan"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kawalan ditambah.</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Lihat mesej terbaharu, panggilan terlepas dan kemaskinian status"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Perbualan"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"Dijeda oleh Jangan Ganggu"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> menghantar mesej: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> menghantar imej"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> mempunyai kemaskinian status: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Masalah membaca meter bateri anda"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ketik untuk mendapatkan maklumat lanjut"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 7256584..d2db76a 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"အစွန်းသို့ရွှေ့ပြီး ဝှက်ရန်"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"အစွန်းမှရွှေ့ပြီး ပြရန်"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ပြောင်းရန်"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"ပင်မ ထိန်းချုပ်မှုများ"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"စက်ထိန်းစနစ်"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ထိန်းချုပ်မှုများထည့်ရန် အက်ပ်ရွေးခြင်း"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">ခလုတ် <xliff:g id="NUMBER_1">%s</xliff:g> ခု ထည့်လိုက်သည်။</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> က မက်ဆေ့ဂျ်ပို့လိုက်သည်- <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> က ပုံပို့လိုက်သည်"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> က အခြေအနေ အပ်ဒိတ်လုပ်လိုက်သည်- <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"ချိတ်ဆက်နိုင်သည်"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"သင်၏ ဘက်ထရီမီတာကို ဖတ်ရာတွင် ပြဿနာရှိနေသည်"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"နောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"နှိုးစက်ပေးမထားပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index f6613ae..7a42d3e 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flytt til kanten og skjul"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flytt ut kanten og vis"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"slå av/på"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Hjemkontroller"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Enhetsstyring"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Velg en app for å legge til kontroller"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kontroller er lagt til.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> har sendt en melding: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> har sendt et bilde"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> har en statusoppdatering: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Tilgjengelig"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kunne ikke lese batterimåleren"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Trykk for å få mer informasjon"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ingen alarm angitt"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index b758747..253419a 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"किनारामा सार्नुहोस् र नदेखिने पार्नु…"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"किनाराबाट सार्नुहोस् र देखिने पार्नु…"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"टगल गर्नुहोस्"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"घरायसी उपकरणका नियन्त्रणहरू"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"डिभाइस नियन्त्रण गर्ने विजेटहरू"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"कन्ट्रोल थप्नु पर्ने एप छान्नुहोस्"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> वटा नियन्त्र थपियो।</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ले एउटा म्यासेज पठाउनुभएको छ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ले एउटा फोटो पठाउनुभयो"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ले स्ट्याटस अपडेट गर्नुभएको छ: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"उपलब्ध"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"डिभाइसको ब्याट्रीको मिटर रिडिङ क्रममा समस्या भयो"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"थप जानकारी प्राप्त गर्न ट्याप गर्नुहोस्"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"अलार्म राखिएको छैन"</string>
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index e6165ee..461505f 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -42,4 +42,10 @@
<item name="android:textColorPrimary">?android:attr/textColorPrimaryInverse</item>
</style>
+ <style name="Theme.PeopleTileConfigActivity" parent="@style/Theme.SystemUI">
+ <item name="android:windowActionBar">false</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowLightStatusBar">false</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 02e08c7e..f0cc269 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Naar rand verplaatsen en verbergen"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Over rand verplaatsen en tonen"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"schakelen"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Bediening voor in huis"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Apparaatbediening"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Kies de app waaraan je bedieningselementen wilt toevoegen"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> bedieningselementen toegevoegd.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> heeft een bericht gestuurd: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> heeft een afbeelding gestuurd"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> heeft een statusupdate: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Beschikbaar"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probleem bij het lezen van je batterijmeter"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tik hier voor meer informatie"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Geen wekker gezet"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 1f4023c..fed17d2d4 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ଧାରକୁ ମୁଭ୍ କରି ଲୁଚାନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ଧାର ବାହାରକୁ ମୁଭ୍ କରି ଦେଖାନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ଟୋଗଲ୍ କରନ୍ତୁ"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"ହୋମ୍ କଣ୍ଟ୍ରୋଲ୍"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଯୋଗ କରିବାକୁ ଆପ୍ ବାଛନ୍ତୁ"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g>ଟି ନିୟନ୍ତ୍ରଣ ଯୋଗ କରାଯାଇଛି।</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ଏକ ମେସେଜ୍ ପଠାଇଛନ୍ତି: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ଏକ ଛବି ପଠାଇଛନ୍ତି"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ଏକ ସ୍ଥିତି ଅପଡେଟ୍ କରିଛନ୍ତି: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ଆପଣଙ୍କ ବ୍ୟାଟେରୀ ମିଟର୍ ପଢ଼ିବାରେ ସମସ୍ୟା ହେଉଛି"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ଅଧିକ ସୂଚନା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ଆଲାରାମ ସେଟ୍ ହୋଇନାହିଁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index fcda32b..fe6118e 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ਕਿਨਾਰੇ ਵਿੱਚ ਲਿਜਾ ਕੇ ਲੁਕਾਓ"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ਕਿਨਾਰੇ ਤੋਂ ਬਾਹਰ ਕੱਢ ਕੇ ਦਿਖਾਓ"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ਟੌਗਲ ਕਰੋ"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"ਹੋਮ ਕੰਟਰੋਲ"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"ਡੀਵਾਈਸ ਕੰਟਰੋਲ"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਐਪ ਚੁਣੋ"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ।</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"ਹਾਲੀਆ ਸੁਨੇਹੇ, ਮਿਸ ਕਾਲਾਂ ਅਤੇ ਸਥਿਤੀ ਸੰਬੰਧੀ ਅੱਪਡੇਟ ਦੇਖੋ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"ਗੱਲਬਾਤ"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਵਿਸ਼ੇਸ਼ਤਾ ਨੇ ਰੋਕ ਦਿੱਤਾ"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਸੁਨੇਹਾ ਭੇਜਿਆ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਇੱਕ ਚਿੱਤਰ ਭੇਜਿਆ ਹੈ"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਸਥਿਤੀ ਅੱਪਡੇਟ ਕੀਤੀ ਹੈ: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ਤੁਹਾਡੇ ਬੈਟਰੀ ਮੀਟਰ ਨੂੰ ਪੜ੍ਹਨ ਵਿੱਚ ਸਮੱਸਿਆ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 6545da6..06757c7 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -1054,7 +1054,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Przenieś do krawędzi i ukryj"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Przenieś poza krawędź i pokaż"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"przełącz"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Sterowanie domem"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Sterowanie urządzeniami"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Wybierz aplikację, do której chcesz dodać elementy sterujące"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="few">Dodano <xliff:g id="NUMBER_1">%s</xliff:g> elementy sterujące</item>
@@ -1161,6 +1161,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> wysyła wiadomość: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> wysyła zdjęcie"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ma nowy stan: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Użytkownik dostępny"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem z odczytaniem pomiaru wykorzystania baterii"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Kliknij, aby uzyskać więcej informacji"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nie ustawiono alarmu"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 0bdbd00..24015d8 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover para a borda e ocultar"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover para fora da borda e exibir"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alternar"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Automação residencial"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> controle adicionado.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma mensagem: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma imagem"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> atualizou o status: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Disponível"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema para ler seu medidor de bateria"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toque para mais informações"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nenhum alarme definido"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 0134b7c..f1a4e03 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover p/ extremidade e ocultar"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Retirar extremidade e mostrar"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ativar/desativar"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Controlo casa"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Controlos de dispositivos"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha uma app para adicionar controlos"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controlos adicionados.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma mensagem: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma imagem"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> tem uma atualização de estado: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Ocorreu um problema ao ler o medidor da bateria"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toque para obter mais informações"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nenhum alarme defin."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 0bdbd00..24015d8 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover para a borda e ocultar"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover para fora da borda e exibir"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alternar"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Automação residencial"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> controle adicionado.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma mensagem: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma imagem"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> atualizou o status: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Disponível"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema para ler seu medidor de bateria"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toque para mais informações"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nenhum alarme definido"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 2916854..c96e3bf 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -1049,7 +1049,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mutați în afară și ascundeți"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mutați în afară și afișați"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"Activați / dezactivați"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Comenzi pentru locuință"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Comenzile dispozitivelor"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Alegeți aplicația pentru a adăuga comenzi"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="few">S-au adăugat <xliff:g id="NUMBER_1">%s</xliff:g> comenzi.</item>
@@ -1152,10 +1152,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Vedeți mesaje recente, apeluri pierdute și actualizări de stare"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversație"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"Întrerupt de Nu deranja"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> a trimis un mesaj: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a trimis o imagine"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> are o nouă stare: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problemă la citirea măsurării bateriei"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Atingeți pentru mai multe informații"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 877e139..ca476c1 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -1054,7 +1054,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Перенести к краю и скрыть"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Вернуть из-за края и показать"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"включить или отключить"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Автоматизация дома"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Управление устройствами"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Чтобы добавить виджеты управления, выберите приложение"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one">Добавлен <xliff:g id="NUMBER_1">%s</xliff:g> элемент управления.</item>
@@ -1158,10 +1158,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Будьте в курсе последних сообщений, пропущенных вызовов и обновлений статуса."</string>
<string name="people_tile_title" msgid="6589377493334871272">"Чат"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"Приостановлено в режиме \"Не беспокоить\""</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"Пользователь <xliff:g id="NAME">%1$s</xliff:g> отправил сообщение: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"Пользователь <xliff:g id="NAME">%1$s</xliff:g> отправил изображение"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"Пользователь <xliff:g id="NAME">%1$s</xliff:g> обновил статус: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Не удается получить данные об уровне заряда батареи"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Нажмите, чтобы узнать больше."</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 7224e17..6cf9f9b 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"මායිමට ගෙන යන්න සහ සඟවන්න"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"මායිමෙන් පිටට ගන්න සහ පෙන්වන්න"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ටොගල් කරන්න"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"නිවෙස් පාලන"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"උපාංග පාලන"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"පාලන එක් කිරීමට යෙදුම තෝරා ගන්න"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one">පාලන <xliff:g id="NUMBER_1">%s</xliff:g>ක් එක් කරන ලදී.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> පණිවිඩයක් එවා ඇත: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> රූපයක් යවන ලදී"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> හට තත්ත්ව යාවත්කාලීනයක් ඇත: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"තිබේ"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ඔබගේ බැටරි මනුව කියවීමේ දෝෂයකි"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"තවත් තොරතුරු සඳහා තට්ටු කරන්න"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"එලාම සකසා නැත"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 3499d93..0f91d81 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -1054,7 +1054,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Presunúť k okraju a skryť"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Presunúť z okraja a zobraziť"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"prepínač"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Ovládanie domácnosti"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Ovládanie zariadení"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Vyberte aplikáciu, ktorej ovládače si chcete pridať"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="few">Boli pridané <xliff:g id="NUMBER_1">%s</xliff:g> ovládacie prvky.</item>
@@ -1158,10 +1158,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Pozrite si nedávne správy, zmeškané hovory a aktualizácie stavu"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Konverzácia"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"Pozastavené režimom bez vyrušení"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> poslal(a) správu: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> poslal(a) obrázok"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> má aktualizáciu statusu: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Pri čítaní meradla batérie sa vyskytol problém"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Klepnutím si zobrazíte ďalšie informácie"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index b11023b..6bc27d0 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -1054,7 +1054,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premakni na rob in skrij"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Premakni z roba in pokaži"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"preklop"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Kontrolniki za dom"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Kontrolniki naprave"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Izberite aplikacijo za dodajanje kontrolnikov"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> kontrolnik dodan.</item>
@@ -1161,6 +1161,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"Oseba <xliff:g id="NAME">%1$s</xliff:g> je poslala sporočilo: <xliff:g id="NOTIFICATION">%2$s</xliff:g>."</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"Oseba <xliff:g id="NAME">%1$s</xliff:g> je poslala sliko."</string>
<string name="new_status_content_description" msgid="6046637888641308327">"Oseba <xliff:g id="NAME">%1$s</xliff:g> je posodobila stanje: <xliff:g id="STATUS">%2$s</xliff:g>."</string>
+ <string name="person_available" msgid="2318599327472755472">"Na voljo"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Težava z branjem indikatorja stanja napolnjenosti baterije"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dotaknite se za več informacij"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ni nastavljenih alarmov"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index dc08fa6..cee829e 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Zhvendose te skaji dhe fshihe"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Zhvendose jashtë skajit dhe shfaqe"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aktivizo/çaktivizo"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Kontrollet e shtëpisë"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Kontrollet e pajisjes"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Zgjidh aplikacionin për të shtuar kontrollet"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">U shtuan <xliff:g id="NUMBER_1">%s</xliff:g> kontrolle.</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Shiko mesazhet e fundit, telefonatat e humbura dhe përditësimet e statusit"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Biseda"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"Vendosur në pauzë nga \"Mos shqetëso\""</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> dërgoi një mesazh: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> dërgoi një imazh"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ka një përditësim të statusit: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem me leximin e matësit të baterisë"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Trokit për më shumë informacione"</string>
@@ -1161,29 +1161,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Përdor gjurmën e gishtit për ta hapur"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kërkohet vërtetimi. Prek sensorin e gjurmës së gishtit për t\'u vërtetuar."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonatë në vazhdim"</string>
- <!-- no translation found for airplane_mode (2536350001462130668) -->
- <skip />
- <!-- no translation found for mobile_data_settings_title (3955246641380064901) -->
- <skip />
- <!-- no translation found for preference_summary_default_combination (8453246369903749670) -->
- <skip />
+ <string name="airplane_mode" msgid="2536350001462130668">"Modaliteti i aeroplanit"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Të dhënat celulare"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Lidhur"</string>
- <!-- no translation found for mobile_data_off_summary (5621158216585822679) -->
- <skip />
+ <string name="mobile_data_off_summary" msgid="5621158216585822679">"Interneti nuk do të lidhet automatikisht"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Nuk ka lidhje"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nuk ofrohet asnjë rrjet tjetër"</string>
<string name="all_network_unavailable" msgid="4112774339909373349">"Nuk ofrohet asnjë rrjet"</string>
- <!-- no translation found for turn_on_wifi (1308379840799281023) -->
- <skip />
- <!-- no translation found for pref_title_network_details (1639455355897668883) -->
- <!-- no translation found for pref_title_network_details (7329759534269363308) -->
- <skip />
- <!-- no translation found for tap_a_network_to_connect (1565073330852369558) -->
- <skip />
- <!-- no translation found for wifi_empty_list_wifi_on (3864376632067585377) -->
- <skip />
- <!-- no translation found for wifi_failed_connect_message (4161863112079000071) -->
- <skip />
- <!-- no translation found for see_all_networks (3773666844913168122) -->
- <skip />
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Detajet e rrjetit"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Trokit te një rrjet për t\'u lidhur"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Po kërkon për rrjete…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Lidhja me rrjetin dështoi"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Shiko të gjitha"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 6140916..0670a9c 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -1049,7 +1049,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Премести до ивице и сакриј"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Премести изван ивице и прикажи"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"укључите/искључите"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Контроле за дом"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Контроле уређаја"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Одаберите апликацију за додавање контрола"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> контрола је додата.</item>
@@ -1155,6 +1155,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> је послао/ла поруку: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> шаље слику"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> има ажурирање статуса: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Доступно"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Проблем са очитавањем мерача батерије"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Додирните за више информација"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Аларм није подешен"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 6a4a37f..b77205e 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flytta till kanten och dölj"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flytta från kanten och visa"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aktivera och inaktivera"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Hemstyrning"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Enhetsstyrning"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Välj en app om du vill lägga till snabbkontroller"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kontroller har lagts till.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> skickade ett meddelande: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> skickade en bild"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> har gjort en statusuppdatering: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batteriindikatorn visas inte"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tryck för mer information"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Inget inställt alarm"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 2a5cbc9..0ba5d05 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Sogeza kwenye ukingo kisha ufiche"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Sogeza nje ya ukingo kisha uonyeshe"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"geuza"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Udhibiti wa vifaa nyumbani"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Vidhibiti vya vifaa"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Chagua programu ili uweke vidhibiti"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">Umeweka vidhibiti <xliff:g id="NUMBER_1">%s</xliff:g>.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ametuma ujumbe: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ametuma picha"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ana taarifa kuhusu hali: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Anapatikana"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Tatizo la kusoma mita ya betri yako"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Gusa ili upate maelezo zaidi"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Hujaweka kengele"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index eaf5d7d..4de2ab5 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -936,7 +936,7 @@
<string name="tuner_lock_screen" msgid="2267383813241144544">"லாக் ஸ்கிரீன்"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"வெப்பத்தினால் ஃபோன் ஆஃப் செய்யப்பட்டது"</string>
<string name="thermal_shutdown_message" msgid="6142269839066172984">"இப்போது உங்கள் மொபைல் இயல்புநிலையில் இயங்குகிறது.\nமேலும் தகவலுக்கு தட்டவும்"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"உங்கள் ஃபோன் அதிகமாகச் சூடானதால், அதன் சூட்டைக் குறைக்க, ஆஃப் செய்யப்பட்டது. இப்போது உங்கள் ஃபோன் இயல்புநிலையில் இயங்குகிறது.\n\nபின்வருவனவற்றைச் செய்தால், ஃபோன் சூடாகலாம்:\n • அதிகளவு தரவைப் பயன்படுத்தும் ஆப்ஸை (எ.கா: கேமிங், வீடியோ (அ) வழிகாட்டுதல் ஆப்ஸ்) பயன்படுத்துவது\n • பெரிய கோப்புகளைப் பதிவிறக்குவது/பதிவேற்றுவது\n • அதிக வெப்பநிலையில் ஃபோனைப் பயன்படுத்துவது"</string>
+ <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"உங்கள் ஃபோன் அதிகமாகச் சூடானதால், அதன் சூட்டைக் குறைக்க, ஆஃப் செய்யப்பட்டது. இப்போது உங்கள் ஃபோன் இயல்புநிலையில் இயங்குகிறது.\n\nபின்வருவனவற்றைச் செய்தால், ஃபோன் சூடாகலாம்:\n • அதிகளவு தரவைப் பயன்படுத்தும் ஆப்ஸை (எ.கா: கேமிங், வீடியோ (அ) வழிகாட்டுதல் ஆப்ஸ்) பயன்படுத்துவது\n • பெரிய ஃபைல்களைப் பதிவிறக்குவது/பதிவேற்றுவது\n • அதிக வெப்பநிலையில் ஃபோனைப் பயன்படுத்துவது"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string>
<string name="high_temp_title" msgid="2218333576838496100">"மொபைல் சூடாகிறது"</string>
<string name="high_temp_notif_message" msgid="1277346543068257549">"மொபைலின் வெப்ப அளவு குறையும் வரை சில அம்சங்களைப் பயன்படுத்த முடியாது.\nமேலும் தகவலுக்கு தட்டவும்"</string>
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ஓரத்திற்கு நகர்த்தி மறை"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ஓரத்திற்கு நகர்த்தி, காட்டு"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"நிலைமாற்று"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"முகப்புக் கட்டுப்பாடுகள்"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"சாதனக் கட்டுப்பாடுகள்"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"கட்டுப்பாடுகளைச் சேர்க்க வேண்டிய ஆப்ஸைத் தேர்ந்தெடுங்கள்"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> கட்டுப்பாடுகள் சேர்க்கப்பட்டன.</item>
@@ -1146,11 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"சமீபத்திய மெசேஜ்களையும் தவறிய அழைப்புகளையும் ஸ்டேட்டஸ் அப்டேட்களையும் பார்க்கலாம்"</string>
<string name="people_tile_title" msgid="6589377493334871272">"உரையாடல்"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"தொந்தரவு செய்ய வேண்டாம் அம்சத்தால் இடைநிறுத்தப்பட்டது"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ஒரு மெசேஜ் அனுப்பியுள்ளார்: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ஒரு படம் அனுப்பியுள்ளார்"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
- <skip />
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> புதிய ஸ்டேட்டஸ் வைத்துள்ளார்: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"ஆன்லைனில் இருக்கிறார்"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"பேட்டரி அளவை அறிவதில் சிக்கல்"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"மேலும் தகவல்களுக்கு தட்டவும்"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"அலாரம் எதுவுமில்லை"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index d1fbb34..5b15cff 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"అంచుకు తరలించి దాచండి"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"అంచుని తరలించి చూపించు"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"టోగుల్ చేయి"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"హోమ్ కంట్రోల్స్"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"డివైజ్ కంట్రోల్స్"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"కంట్రోల్స్ను యాడ్ చేయడానికి యాప్ను ఎంచుకోండి"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> కంట్రోల్లు యాడ్ అయ్యాయి.</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"ఇటీవలి మెసేజ్లు, మిస్డ్ కాల్లు, అలాగే స్టేటస్ అప్డేట్లను చూడండి"</string>
<string name="people_tile_title" msgid="6589377493334871272">"సంభాషణ"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"అంతరాయం కలిగించవద్దు ద్వారా పాజ్ చేయబడింది"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> మెసేజ్ను పంపారు: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ఇమేజ్ను పంపారు"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>, స్టేటస్ను గురించిన అప్డేట్ను కలిగి ఉన్నారు: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"మీ బ్యాటరీ మీటర్ను చదవడంలో సమస్య"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"మరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
@@ -1161,29 +1161,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"తెరవడానికి వేలిముద్రను ఉపయోగించండి"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ప్రామాణీకరణ అవసరం. ప్రామాణీకరించడానికి వేలిముద్ర సెన్సార్ను తాకండి."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ఫోన్ కాల్ జరుగుతోంది"</string>
- <!-- no translation found for airplane_mode (2536350001462130668) -->
- <skip />
- <!-- no translation found for mobile_data_settings_title (3955246641380064901) -->
- <skip />
- <!-- no translation found for preference_summary_default_combination (8453246369903749670) -->
- <skip />
+ <string name="airplane_mode" msgid="2536350001462130668">"విమానం మోడ్"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"మొబైల్ డేటా"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"కనెక్ట్ చేయబడింది"</string>
- <!-- no translation found for mobile_data_off_summary (5621158216585822679) -->
- <skip />
+ <string name="mobile_data_off_summary" msgid="5621158216585822679">"ఇంటర్నెట్ ఆటోమెటిక్గా కనెక్ట్ అవ్వదు"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"కనెక్షన్ లేదు"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"ఇతర నెట్వర్క్లేవీ అందుబాటులో లేవు"</string>
<string name="all_network_unavailable" msgid="4112774339909373349">"నెట్వర్క్లు అందుబాటులో లేవు"</string>
- <!-- no translation found for turn_on_wifi (1308379840799281023) -->
- <skip />
- <!-- no translation found for pref_title_network_details (1639455355897668883) -->
- <!-- no translation found for pref_title_network_details (7329759534269363308) -->
- <skip />
- <!-- no translation found for tap_a_network_to_connect (1565073330852369558) -->
- <skip />
- <!-- no translation found for wifi_empty_list_wifi_on (3864376632067585377) -->
- <skip />
- <!-- no translation found for wifi_failed_connect_message (4161863112079000071) -->
- <skip />
- <!-- no translation found for see_all_networks (3773666844913168122) -->
- <skip />
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"నెట్వర్క్ వివరాలు"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"కనెక్ట్ చేయడానికి నెట్వర్క్ను ట్యాప్ చేయండి"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"నెట్వర్క్ల కోసం సెర్చ్ చేస్తోంది…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"నెట్వర్క్కు కనెక్ట్ చేయడం విఫలమైంది"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"అన్నీ చూడండి"</string>
</resources>
diff --git a/packages/SystemUI/res/values-television/dimens.xml b/packages/SystemUI/res/values-television/dimens.xml
index c258fcc..76c620d 100644
--- a/packages/SystemUI/res/values-television/dimens.xml
+++ b/packages/SystemUI/res/values-television/dimens.xml
@@ -38,7 +38,7 @@
<dimen name="bottom_sheet_min_height">208dp</dimen>
<dimen name="bottom_sheet_margin">24dp</dimen>
- <dimen name="bottom_sheet_background_blur_radius">120dp</dimen>
+ <dimen name="bottom_sheet_background_blur_radius">37dp</dimen>
<dimen name="privacy_chip_margin">12dp</dimen>
<dimen name="privacy_chip_icon_margin_in_between">9dp</dimen>
@@ -56,4 +56,4 @@
<dimen name="privacy_chip_dot_bg_height">18dp</dimen>
<dimen name="privacy_chip_dot_bg_radius">9dp</dimen>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index eadbd29..8b0a90f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ย้ายไปที่ขอบและซ่อน"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ย้ายออกจากขอบและแสดง"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"สลับ"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"ระบบควบคุมอุปกรณ์ในบ้าน"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"ระบบควบคุมอุปกรณ์"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"เลือกแอปเพื่อเพิ่มตัวควบคุม"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">เพิ่มตัวควบคุม <xliff:g id="NUMBER_1">%s</xliff:g> ตัวแล้ว</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ส่งข้อความ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ส่งรูปภาพ"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> มีการอัปเดตสถานะ: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"พบปัญหาในการอ่านเครื่องวัดแบตเตอรี่"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"แตะดูข้อมูลเพิ่มเติม"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ไม่มีการตั้งปลุก"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index a0757f4..02195ab 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Ilipat sa sulok at itago"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Alisin sa sulok at ipakita"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"i-toggle"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Mga Home control"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Mga kontrol ng device"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Pumili ng app para magdagdag ng mga kontrol"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> kontrol ang naidagdag.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"Nagpadala si <xliff:g id="NAME">%1$s</xliff:g> ng mensahe: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"Nagpadala si <xliff:g id="NAME">%1$s</xliff:g> ng larawan"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"May update sa status si <xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nagkaproblema sa pagbabasa ng iyong battery meter"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"I-tap para sa higit pang impormasyon"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Walang alarm"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index dbfa9cd..b7ad7cb 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Kenara taşıyıp gizle"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Kenarın dışına taşıyıp göster"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"değiştir"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Ev kontrolleri"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Cihaz denetimleri"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Denetim eklemek için uygulama seçin"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kontrol eklendi.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> bir mesaj gönderdi: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> bir resim gönderdi"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>, durumunu güncelledi: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Pil ölçeriniz okunurken sorun oluştu"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Daha fazla bilgi için dokunun"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarm ayarlanmadı"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 70340a5..204414c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -676,7 +676,7 @@
<string name="wallet_app_button_label" msgid="7123784239111190992">"Показати все"</string>
<string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Розблокувати, щоб сплатити"</string>
<string name="wallet_secondary_label_no_card" msgid="530725155985223497">"Додати картку"</string>
- <string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Триває оновлення"</string>
+ <string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Оновлення"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Розблокувати, щоб використовувати"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Не вдалось отримати ваші картки. Повторіть спробу пізніше."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Параметри блокування екрана"</string>
@@ -1054,7 +1054,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Перемістити до краю, приховати"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Перемістити від краю, показати"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"перемкнути"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Автоматизація дому"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Керування пристроями"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Виберіть, для якого додатка налаштувати елементи керування"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one">Додано <xliff:g id="NUMBER_1">%s</xliff:g> елемент керування.</item>
@@ -1161,6 +1161,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> надсилає повідомлення: \"<xliff:g id="NOTIFICATION">%2$s</xliff:g>\""</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> надсилає зображення"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> публікує новий статус: \"<xliff:g id="STATUS">%2$s</xliff:g>\""</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Не вдалось отримати дані лічильника акумулятора"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Натисніть, щоб дізнатися більше"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Немає будильників"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 768371b..0692044 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"EDGE پر لے جائیں اور چھپائیں"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"EDGE اور شو سے باہر منتقل کریں"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ٹوگل کریں"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"ہوم کنٹرولز"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"آلہ کے کنٹرولز"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"کنٹرولز شامل کرنے کے لیے ایپ منتخب کریں"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> کنٹرولز شامل کر دیے گئے۔</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"حالیہ پیغامات، چھوٹی ہوئی کالز اور اسٹیٹس اپ ڈیٹس دیکھیں"</string>
<string name="people_tile_title" msgid="6589377493334871272">"گفتگو"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"\'ڈسٹرب نہ کریں\' کے ذریعے موقوف کیا گیا"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> نے ایک پیغام بھیجا: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> نے ایک تصویر بھیجی"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> نے اسٹیٹس کو اپ ڈیٹ کر دیا ہے: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"آپ کے بیٹری میٹر کو پڑھنے میں دشواری"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"مزید معلومات کے لیے تھپتھپائیں"</string>
@@ -1161,29 +1161,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"کھولنے کے لیے فنگر پرنٹ کا استعمال کریں"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"توثیق مطلوب ہے۔ توثیق کرنے کے لیے فنگر پرنٹ سینسر کو ٹچ کریں۔"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"جاری فون کال"</string>
- <!-- no translation found for airplane_mode (2536350001462130668) -->
- <skip />
- <!-- no translation found for mobile_data_settings_title (3955246641380064901) -->
- <skip />
- <!-- no translation found for preference_summary_default_combination (8453246369903749670) -->
- <skip />
+ <string name="airplane_mode" msgid="2536350001462130668">"ہوائی جہاز وضع"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"موبائل ڈیٹا"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="NETWORKMODE">%2$s</xliff:g> / <xliff:g id="STATE">%1$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"منسلک ہے"</string>
- <!-- no translation found for mobile_data_off_summary (5621158216585822679) -->
- <skip />
+ <string name="mobile_data_off_summary" msgid="5621158216585822679">"انٹرنیٹ خود کار طور پر منسلک نہیں ہوگا"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"کوئی کنکشن نہیں"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"کوئی دوسرا نیٹ ورک دستیاب نہیں ہے"</string>
<string name="all_network_unavailable" msgid="4112774339909373349">"کوئی نیٹ ورکس دستیاب نہیں ہیں"</string>
- <!-- no translation found for turn_on_wifi (1308379840799281023) -->
- <skip />
- <!-- no translation found for pref_title_network_details (1639455355897668883) -->
- <!-- no translation found for pref_title_network_details (7329759534269363308) -->
- <skip />
- <!-- no translation found for tap_a_network_to_connect (1565073330852369558) -->
- <skip />
- <!-- no translation found for wifi_empty_list_wifi_on (3864376632067585377) -->
- <skip />
- <!-- no translation found for wifi_failed_connect_message (4161863112079000071) -->
- <skip />
- <!-- no translation found for see_all_networks (3773666844913168122) -->
- <skip />
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"نیٹ ورک کی تفصیلات"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"منسلک کرنے کے لیے نیٹ ورک پر تھپتھپائیں"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"نیٹ ورکس تلاش کیے جا رہے ہیں…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"نیٹ ورک سے منسلک ہونے میں ناکام ہو گیا"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"سبھی دیکھیں"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 60b2fec..fae90c8 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Chetiga olib borish va yashirish"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Chetidan qaytarish va koʻrsatish"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"oʻzgartirish"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Uy boshqaruvi"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Qurilmalarni boshqarish"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Boshqaruv elementlarini kiritish uchun ilovani tanlang"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> ta nazorat kiritilgan.</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> xabar yubordi: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> rasm yubordi"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ahvolini yangiladi: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"Mavjud"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batareya quvvati aniqlanmadi"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Batafsil axborot olish uchun bosing"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Signal sozlanmagan"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index fab7c31..891d27d 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Chuyển đến cạnh và ẩn"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Chuyển ra xa cạnh và hiển thị"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"bật/tắt"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Điều khiển nhà"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Điều khiển thiết bị"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Chọn ứng dụng để thêm các tùy chọn điều khiển"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">Đã thêm <xliff:g id="NUMBER_1">%s</xliff:g> tùy chọn điều khiển.</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"Xem các tin nhắn, cuộc gọi nhỡ và thông tin cập nhật trạng thái gần đây"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Cuộc trò chuyện"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"Đã tạm dừng do chế độ Không làm phiền"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> đã gửi một tin nhắn: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> đã gửi một hình ảnh"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> đã cập nhật trạng thái: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Đã xảy ra vấn đề khi đọc dung lượng pin của bạn"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Nhấn để biết thêm thông tin"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 5f1b5cb..f46cc60 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"移至边缘并隐藏"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"移至边缘以外并显示"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"开启/关闭"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"家居控制"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"设备控制器"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"选择要添加控制器的应用"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">已添加 <xliff:g id="NUMBER_1">%s</xliff:g> 个控件。</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"查看近期的消息、未接电话和状态更新"</string>
<string name="people_tile_title" msgid="6589377493334871272">"对话"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"勿扰模式已暂停通知"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>发送了一条消息:<xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>发送了一张图片"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>更新了状态:<xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"读取电池计量器时出现问题"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"点按即可了解详情"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index bb98fb9..9e498f6 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"移到邊緣並隱藏"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"從邊緣移出並顯示"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"切換"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"智能家居"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"裝置控制"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"選擇要新增控制項的應用程式"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">已新增 <xliff:g id="NUMBER_1">%s</xliff:g> 個控制項。</item>
@@ -1149,6 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>傳送了訊息:<xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>傳送了圖片"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>有狀態更新:<xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <string name="person_available" msgid="2318599327472755472">"有空"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"讀取電池計量器時發生問題"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"輕按即可瞭解詳情"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"未設定鬧鐘"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 41e57f3..2cb78a7 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"移到邊緣並隱藏"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"從邊緣移出並顯示"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"切換"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"居家控制系統"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"裝置控制"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"選擇應用程式以新增控制項"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">已新增 <xliff:g id="NUMBER_1">%s</xliff:g> 個控制項。</item>
@@ -1146,10 +1146,10 @@
<string name="people_tile_description" msgid="8154966188085545556">"查看最近的訊息、未接來電和狀態更新"</string>
<string name="people_tile_title" msgid="6589377493334871272">"對話"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"零打擾模式已將通知暫停"</string>
- <!-- no translation found for new_notification_text_content_description (2915029960094389291) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>傳送了一則訊息:<xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>傳送了一張圖片"</string>
- <!-- no translation found for new_status_content_description (6046637888641308327) -->
+ <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>更新了狀態:<xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
<skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"讀取電池計量器時發生問題"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"輕觸即可瞭解詳情"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 5f0ff02..a3c87f5 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -1044,7 +1044,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Hamba onqenqemeni ufihle"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Phuma onqenqemeni ubonise"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"guqula"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Izilawuli zasekhaya"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Izilawuli zezinsiza"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Khetha uhlelo lokusebenza ukwengeza izilawuli"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> ukulawulwa okwengeziwe.</item>
@@ -1149,6 +1149,8 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"U-<xliff:g id="NAME">%1$s</xliff:g> uthumele umlayezo: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"U-<xliff:g id="NAME">%1$s</xliff:g> uthumele isithombe"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"U-<xliff:g id="NAME">%1$s</xliff:g> unesibuyekezo sesimo: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
+ <!-- no translation found for person_available (2318599327472755472) -->
+ <skip />
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kube khona inkinga ngokufunda imitha yakho yebhethri"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Thepha ukuze uthole olunye ulwazi"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Akukho alamu esethiwe"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c160946..22035f4 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -62,7 +62,9 @@
<item name="navigation_luminance_change_threshold" type="dimen" format="float">0.05</item>
<dimen name="floating_rotation_button_diameter">40dp</dimen>
- <dimen name="floating_rotation_button_min_margin">4dp</dimen>
+ <dimen name="floating_rotation_button_min_margin">20dp</dimen>
+ <dimen name="floating_rotation_button_taskbar_left_margin">20dp</dimen>
+ <dimen name="floating_rotation_button_taskbar_bottom_margin">10dp</dimen>
<!-- Height of notification icons in the status bar -->
<dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
@@ -402,8 +404,11 @@
<dimen name="status_bar_header_padding_bottom">48dp</dimen>
<!-- The height of the container that holds the battery and time in the quick settings header.
+ Preferred over using "@*android:dimen/quick_qs_offset_height" as system icons are not always
+ present in quick settings (e.g. in split shade) and it's useful to be able to override this
+ value in such cases.
-->
- <dimen name="qs_header_system_icons_area_height">48dp</dimen>
+ <dimen name="qs_header_system_icons_area_height">@*android:dimen/quick_qs_offset_height</dimen>
<!-- How far the quick-quick settings panel extends below the status bar -->
<dimen name="qs_quick_header_panel_height">128dp</dimen>
@@ -455,6 +460,10 @@
<!-- Width for the notification panel and related windows -->
<dimen name="match_parent">-1px</dimen>
+ <!-- Height of status bar in split shade mode - visible only on large screens -->
+ <dimen name="split_shade_header_height">@*android:dimen/quick_qs_offset_height</dimen>
+ <dimen name="split_shade_header_min_height">@dimen/qs_header_row_min_height</dimen>
+
<!-- The top margin of the panel that holds the list of notifications. -->
<dimen name="notification_panel_margin_top">0dp</dimen>
@@ -623,6 +632,7 @@
<dimen name="qs_footer_icon_size">20dp</dimen>
<dimen name="qs_header_top_padding">15dp</dimen>
<dimen name="qs_header_bottom_padding">14dp</dimen>
+ <dimen name="qs_header_row_min_height">48dp</dimen>
<dimen name="qs_footer_padding">20dp</dimen>
<dimen name="qs_security_footer_height">88dp</dimen>
@@ -1245,7 +1255,7 @@
<!-- Blur radius on status bar window and power menu -->
<dimen name="min_window_blur_radius">1px</dimen>
- <dimen name="max_window_blur_radius">72px</dimen>
+ <dimen name="max_window_blur_radius">23px</dimen>
<!-- How much into a DisplayCutout's bounds we can go, on each side -->
<dimen name="display_cutout_margin_consumption">0px</dimen>
@@ -1479,6 +1489,8 @@
<dimen name="content_text_size_for_large">14sp</dimen>
<dimen name="below_name_text_padding">16dp</dimen>
<dimen name="above_notification_text_padding">22dp</dimen>
+ <dimen name="before_messages_count_padding">40dp</dimen>
+ <dimen name="before_predefined_icon_padding">30dp</dimen>
<dimen name="regular_predefined_icon">18dp</dimen>
<dimen name="larger_predefined_icon">24dp</dimen>
<dimen name="largest_predefined_icon">32dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
index 5bd95eb..3dbd990 100644
--- a/packages/SystemUI/res/values/dimens_tv.xml
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -16,5 +16,5 @@
-->
<resources>
<dimen name="tv_notification_panel_width">360dp</dimen>
- <dimen name="tv_notification_blur_radius">100dp</dimen>
-</resources>
\ No newline at end of file
+ <dimen name="tv_notification_blur_radius">31dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index b5a2c56..91d5d79 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -777,6 +777,7 @@
<style name="Theme.PeopleTileConfigActivity" parent="@style/Theme.SystemUI">
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
+ <item name="android:windowLightStatusBar">true</item>
</style>
<style name="TextAppearance.Control">
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index f72245b..11557ad 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -140,5 +140,8 @@
/** Notifies that a swipe-up gesture has started */
oneway void notifySwipeUpGestureStarted() = 46;
- // Next id = 47
+ /** Notifies when taskbar status updated */
+ oneway void notifyTaskbarStatus(boolean visible, boolean stashed) = 47;
+
+ // Next id = 48
}
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 a77cc87..3eea99a 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
@@ -27,6 +27,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
+import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.graphics.Rect;
import android.os.IBinder;
@@ -122,15 +123,20 @@
// This transition is for opening recents, so recents is on-top. We want to draw
// the current going-away task on top of recents, though, so move it to front
WindowContainerToken pausingTask = null;
- SurfaceControl pausingLeash = null;
+ WindowContainerToken pipTask = null;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
if (change.getMode() == TRANSIT_CLOSE || change.getMode() == TRANSIT_TO_BACK) {
t.setLayer(leashMap.get(change.getLeash()),
info.getChanges().size() * 3 - i);
- if (change.getTaskInfo() != null) {
+ final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+ if (taskInfo != null) {
pausingTask = change.getTaskInfo().token;
}
+ if (taskInfo.pictureInPictureParams != null
+ && taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
+ pipTask = change.getTaskInfo().token;
+ }
}
}
// Also make all the wallpapers opaque since we want the visible from the start
@@ -138,7 +144,7 @@
t.setAlpha(wallpapers[i].leash.mSurfaceControl, 1);
}
t.apply();
- mRecentsSession.setup(controller, info, finishedCallback, pausingTask,
+ mRecentsSession.setup(controller, info, finishedCallback, pausingTask, pipTask,
leashMap, mToken);
recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0),
new Rect());
@@ -183,14 +189,17 @@
private RecentsAnimationControllerCompat mWrapped = null;
private IRemoteTransitionFinishedCallback mFinishCB = null;
private WindowContainerToken mPausingTask = null;
+ private WindowContainerToken mPipTask = null;
private TransitionInfo mInfo = null;
private SurfaceControl mOpeningLeash = null;
private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
+ private PictureInPictureSurfaceTransaction mPipTransaction = null;
private IBinder mTransition = null;
void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info,
IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask,
- ArrayMap<SurfaceControl, SurfaceControl> leashMap, IBinder transition) {
+ WindowContainerToken pipTask, ArrayMap<SurfaceControl, SurfaceControl> leashMap,
+ IBinder transition) {
if (mInfo != null) {
throw new IllegalStateException("Trying to run a new recents animation while"
+ " recents is already active.");
@@ -199,6 +208,7 @@
mInfo = info;
mFinishCB = finishCB;
mPausingTask = pausingTask;
+ mPipTask = pipTask;
mLeashMap = leashMap;
mTransition = transition;
}
@@ -257,6 +267,7 @@
@Override public void setFinishTaskTransaction(int taskId,
PictureInPictureSurfaceTransaction finishTransaction, SurfaceControl overlay) {
+ mPipTransaction = finishTransaction;
if (mWrapped != null) {
mWrapped.setFinishTaskTransaction(taskId, finishTransaction, overlay);
}
@@ -288,7 +299,18 @@
t.setAlpha(mOpeningLeash, 1.f);
t.apply();
}
- mFinishCB.onTransitionFinished(null /* wct */, null /* sct */);
+ if (mPipTask != null && mPipTransaction != null) {
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.show(mInfo.getChange(mPipTask).getLeash());
+ PictureInPictureSurfaceTransaction.apply(mPipTransaction,
+ mInfo.getChange(mPipTask).getLeash(), t);
+ mPipTask = null;
+ mPipTransaction = null;
+ mFinishCB.onTransitionFinished(null /* wct */, t);
+ } else {
+ mFinishCB.onTransitionFinished(null /* wct */, null /* sct */);
+ }
+
}
} catch (RemoteException e) {
Log.e("RemoteTransitionCompat", "Failed to call animation finish callback", e);
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java
deleted file mode 100644
index 7b9ebc0..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.shared.system;
-
-import android.app.ActivityManager;
-import android.app.PictureInPictureParams;
-import android.app.TaskInfo;
-import android.content.ComponentName;
-import android.content.pm.ActivityInfo;
-import android.graphics.Rect;
-
-public class TaskInfoCompat {
-
- public static int getUserId(TaskInfo info) {
- return info.userId;
- }
-
- public static int getActivityType(TaskInfo info) {
- return info.configuration.windowConfiguration.getActivityType();
- }
-
- public static int getWindowingMode(TaskInfo info) {
- return info.configuration.windowConfiguration.getWindowingMode();
- }
-
- public static Rect getWindowConfigurationBounds(TaskInfo info) {
- return info.configuration.windowConfiguration.getBounds();
- }
-
- public static boolean supportsSplitScreenMultiWindow(TaskInfo info) {
- return info.supportsSplitScreenMultiWindow;
- }
-
- public static ComponentName getTopActivity(TaskInfo info) {
- return info.topActivity;
- }
-
- public static ActivityManager.TaskDescription getTaskDescription(TaskInfo info) {
- return info.taskDescription;
- }
-
- public static ActivityInfo getTopActivityInfo(TaskInfo info) {
- return info.topActivityInfo;
- }
-
- public static boolean isAutoEnterPipEnabled(PictureInPictureParams params) {
- return params.isAutoEnterEnabled();
- }
-
- public static Rect getPipSourceRectHint(PictureInPictureParams params) {
- return params.getSourceRectHint();
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 2158401..8bf8e09 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -80,18 +80,6 @@
dozeParameters, unlockedScreenOffAnimationController, /* animateYPos= */ true);
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
mSmartspaceTransitionController = smartspaceTransitionController;
-
- mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
- @Override
- public void onKeyguardShowingChanged() {
- // If we explicitly re-show the keyguard, make sure that all the child views are
- // visible. They might have been animating out as part of the SmartSpace shared
- // element transition.
- if (keyguardStateController.isShowing()) {
- mView.setChildrenAlphaExcludingClockView(1f);
- }
- }
- });
}
@Override
@@ -103,12 +91,14 @@
protected void onViewAttached() {
mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
mConfigurationController.addCallback(mConfigurationListener);
+ mKeyguardStateController.addCallback(mKeyguardStateControllerCallback);
}
@Override
protected void onViewDetached() {
mKeyguardUpdateMonitor.removeCallback(mInfoCallback);
mConfigurationController.removeCallback(mConfigurationListener);
+ mKeyguardStateController.removeCallback(mKeyguardStateControllerCallback);
}
/**
@@ -278,6 +268,19 @@
}
};
+ private KeyguardStateController.Callback mKeyguardStateControllerCallback =
+ new KeyguardStateController.Callback() {
+ @Override
+ public void onKeyguardShowingChanged() {
+ // If we explicitly re-show the keyguard, make sure that all the child views are
+ // visible. They might have been animating out as part of the SmartSpace shared
+ // element transition.
+ if (mKeyguardStateController.isShowing()) {
+ mView.setChildrenAlphaExcludingClockView(1f);
+ }
+ }
+ };
+
/**
* Rect that specifies how KSV should be clipped, on its parent's coordinates.
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 1344be6..672e2e6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -285,7 +285,7 @@
@VisibleForTesting
protected boolean mTelephonyCapable;
- private final boolean mAcquiredHapticEnabled;
+ private final boolean mAcquiredHapticEnabled = false;
@Nullable private final Vibrator mVibrator;
// Device provisioning state
@@ -1413,11 +1413,7 @@
@VisibleForTesting
public void playAcquiredHaptic() {
if (mAcquiredHapticEnabled && mVibrator != null) {
- String effect = Settings.Global.getString(
- mContext.getContentResolver(),
- "udfps_acquired_type");
- mVibrator.vibrate(UdfpsController.getVibration(effect,
- UdfpsController.EFFECT_TICK),
+ mVibrator.vibrate(UdfpsController.EFFECT_CLICK,
UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES);
}
}
@@ -1730,8 +1726,6 @@
mLockPatternUtils = lockPatternUtils;
mAuthController = authController;
dumpManager.registerDumpable(getClass().getName(), this);
- mAcquiredHapticEnabled = Settings.Global.getInt(mContext.getContentResolver(),
- "udfps_acquired", 0) == 1;
mVibrator = vibrator;
mHandler = new Handler(mainLooper) {
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 7bbb63f..afea272 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -24,8 +24,8 @@
import android.content.res.Configuration;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.util.DisplayMetrics;
@@ -79,7 +79,8 @@
@NonNull private final DelayableExecutor mExecutor;
private boolean mUdfpsEnrolled;
- @NonNull private final Drawable mUnlockIcon;
+ @NonNull private final AnimatedVectorDrawable mFpToUnlockIcon;
+ @NonNull private final AnimatedVectorDrawable mLockToUnlockIcon;
@NonNull private final Drawable mLockIcon;
@NonNull private final CharSequence mUnlockedLabel;
@NonNull private final CharSequence mLockedLabel;
@@ -133,14 +134,14 @@
mExecutor = executor;
final Context context = view.getContext();
- mUnlockIcon = new InsetDrawable(context.getResources().getDrawable(
- com.android.internal.R.drawable.ic_lock_open, context.getTheme()),
- context.getResources().getDimensionPixelSize(
- com.android.systemui.R.dimen.udfps_unlock_icon_inset));
- mLockIcon = new InsetDrawable(context.getResources().getDrawable(
- com.android.internal.R.drawable.ic_lock, context.getTheme()),
- context.getResources().getDimensionPixelSize(
- com.android.systemui.R.dimen.udfps_unlock_icon_inset));
+ mLockIcon = mView.getContext().getResources().getDrawable(
+ R.anim.lock_to_unlock,
+ mView.getContext().getTheme());
+ mFpToUnlockIcon = (AnimatedVectorDrawable) mView.getContext().getResources().getDrawable(
+ R.anim.fp_to_unlock, mView.getContext().getTheme());
+ mLockToUnlockIcon = (AnimatedVectorDrawable) mView.getContext().getResources().getDrawable(
+ R.anim.lock_to_unlock,
+ mView.getContext().getTheme());
mUnlockedLabel = context.getResources().getString(R.string.accessibility_unlock_button);
mLockedLabel = context.getResources().getString(R.string.accessibility_lock_icon);
dumpManager.registerDumpable("LockIconViewController", this);
@@ -212,6 +213,8 @@
return;
}
+ boolean wasShowingFpIcon = mHasUdfps && !mShowUnlockIcon && !mShowLockIcon;
+ boolean wasShowingLockIcon = mShowLockIcon;
mShowLockIcon = !mCanDismissLockScreen && !mUserUnlockedWithBiometric && isLockScreen()
&& (!mUdfpsEnrolled || !mRunningFPS);
mShowUnlockIcon = mCanDismissLockScreen && isLockScreen();
@@ -222,7 +225,15 @@
mView.setVisibility(View.VISIBLE);
mView.setContentDescription(mLockedLabel);
} else if (mShowUnlockIcon) {
- mView.setImageDrawable(mUnlockIcon);
+ if (wasShowingFpIcon) {
+ mView.setImageDrawable(mFpToUnlockIcon);
+ mFpToUnlockIcon.forceAnimationOnUI();
+ mFpToUnlockIcon.start();
+ } else if (wasShowingLockIcon) {
+ mView.setImageDrawable(mLockToUnlockIcon);
+ mLockToUnlockIcon.forceAnimationOnUI();
+ mLockToUnlockIcon.start();
+ }
mView.setVisibility(View.VISIBLE);
mView.setContentDescription(mUnlockedLabel);
} else {
@@ -272,7 +283,8 @@
private void updateColors() {
final int color = Utils.getColorAttrDefaultColor(mView.getContext(),
R.attr.wallpaperTextColorAccent);
- mUnlockIcon.setTint(color);
+ mFpToUnlockIcon.setTint(color);
+ mLockToUnlockIcon.setTint(color);
mLockIcon.setTint(color);
}
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 54e78cf..6fc2e41 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -192,6 +192,7 @@
* 0 - No preference
* 1 - Force on
* 2 - Force off
+ * 3 - Estimate
* @param mode desired mode (none, on, off)
*/
public void setPercentShowMode(@BatteryPercentMode int mode) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index 17178fa..e521c90 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -310,7 +310,8 @@
}
void onConfigurationChanged(int configDiff) {
- if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) {
+ if ((configDiff & (ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE))
+ != 0) {
final Rect previousDraggableBounds = new Rect(mDraggableWindowBounds);
mDraggableWindowBounds.set(getDraggableWindowBounds());
// Keep the Y position with the same height ratio before the window bounds and
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index cee395b..3281347 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -91,7 +91,7 @@
final Context windowContext = mContext.createWindowContext(display,
TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, /* options */ null);
final WindowMagnificationController controller = new WindowMagnificationController(
- mContext,
+ windowContext,
mHandler, new SfVsyncFrameCallbackProvider(), null,
new SurfaceControl.Transaction(), mWindowMagnifierCallback, mSysUiState);
return new WindowMagnificationAnimationController(windowContext, controller);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.java
index 45ee4ad..ee602bc 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.java
@@ -23,6 +23,8 @@
import android.util.AttributeSet;
import android.util.Log;
+import androidx.annotation.Nullable;
+
import com.android.systemui.R;
public class AuthBiometricFingerprintView extends AuthBiometricView {
@@ -94,12 +96,37 @@
mIconView.setImageDrawable(icon);
+ final CharSequence iconContentDescription = getIconContentDescription(newState);
+ if (iconContentDescription != null) {
+ mIconView.setContentDescription(iconContentDescription);
+ }
+
if (animation != null && shouldAnimateForTransition(lastState, newState)) {
animation.forceAnimationOnUI();
animation.start();
}
}
+ @Nullable
+ private CharSequence getIconContentDescription(int newState) {
+ switch (newState) {
+ case STATE_IDLE:
+ case STATE_AUTHENTICATING_ANIMATING_IN:
+ case STATE_AUTHENTICATING:
+ case STATE_PENDING_CONFIRMATION:
+ case STATE_AUTHENTICATED:
+ return mContext.getString(
+ R.string.accessibility_fingerprint_dialog_fingerprint_icon);
+
+ case STATE_ERROR:
+ case STATE_HELP:
+ return mContext.getString(R.string.biometric_dialog_try_again);
+
+ default:
+ return null;
+ }
+ }
+
private boolean shouldAnimateForTransition(int oldState, int newState) {
switch (newState) {
case STATE_HELP:
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index bebf813..60b0637 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -636,7 +636,6 @@
mIndicatorView.setText(message);
mIndicatorView.setTextColor(mTextColorError);
mIndicatorView.setVisibility(View.VISIBLE);
- mIndicatorView.setSelected(true);
mHandler.postDelayed(resetMessageRunnable, mInjector.getDelayAfterError());
Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index f9103b5..ab3e042e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -16,7 +16,7 @@
package com.android.systemui.biometrics;
-import static android.os.VibrationEffect.Composition.PRIMITIVE_LOW_TICK;
+import static android.hardware.fingerprint.IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -26,7 +26,6 @@
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -46,8 +45,6 @@
import android.os.Trace;
import android.os.VibrationEffect;
import android.os.Vibrator;
-import android.provider.Settings;
-import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -159,16 +156,8 @@
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
- public static final VibrationEffect EFFECT_TICK =
- VibrationEffect.get(VibrationEffect.EFFECT_TICK);
- private static final VibrationEffect EFFECT_TEXTURE_TICK =
- VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK);
- @VisibleForTesting
- static final VibrationEffect EFFECT_CLICK = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
- private static final VibrationEffect EFFECT_HEAVY =
- VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
- private static final VibrationEffect EFFECT_DOUBLE_CLICK =
- VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
+ public static final VibrationEffect EFFECT_CLICK =
+ VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
@Override
@@ -317,8 +306,10 @@
@Override
public void onReceive(Context context, Intent intent) {
if (mServerRequest != null
+ && mServerRequest.mRequestReason != REASON_AUTH_FPM_KEYGUARD
&& Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
- Log.d(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received");
+ Log.d(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received, mRequestReason: "
+ + mServerRequest.mRequestReason);
mServerRequest.onUserCanceled();
mServerRequest = null;
updateOverlay();
@@ -434,7 +425,6 @@
mTouchLogTime = SystemClock.elapsedRealtime();
mPowerManager.userActivity(SystemClock.uptimeMillis(),
PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
- playStartHaptic();
handled = true;
} else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) {
Log.v(TAG, "onTouch | finger move: " + touchInfo);
@@ -549,18 +539,7 @@
@VisibleForTesting
public void playStartHaptic() {
if (mVibrator != null) {
- final ContentResolver contentResolver =
- mContext.getContentResolver();
- // TODO: these settings checks should eventually be removed after ux testing
- // (b/185124905)
- int startEnabled = Settings.Global.getInt(contentResolver,
- "udfps_start", 1);
- if (startEnabled > 0) {
- String startEffectSetting = Settings.Global.getString(
- contentResolver, "udfps_start_type");
- mVibrator.vibrate(getVibration(startEffectSetting,
- EFFECT_CLICK), VIBRATION_SONIFICATION_ATTRIBUTES);
- }
+ mVibrator.vibrate(EFFECT_CLICK, VIBRATION_SONIFICATION_ATTRIBUTES);
}
}
@@ -633,9 +612,12 @@
// Gets the size based on the current rotation of the display.
mContext.getDisplay().getRealSize(p);
- // Transform dimensions if the device is in landscape mode.
+ // Transform dimensions if the device is in landscape mode
switch (mContext.getDisplay().getRotation()) {
case Surface.ROTATION_90:
+ if (animation instanceof UdfpsKeyguardViewController) {
+ break;
+ }
mCoreLayoutParams.x = mSensorProps.sensorLocationY - mSensorProps.sensorRadius
- paddingX;
mCoreLayoutParams.y = p.y - mSensorProps.sensorLocationX - mSensorProps.sensorRadius
@@ -643,6 +625,9 @@
break;
case Surface.ROTATION_270:
+ if (animation instanceof UdfpsKeyguardViewController) {
+ break;
+ }
mCoreLayoutParams.x = p.x - mSensorProps.sensorLocationY - mSensorProps.sensorRadius
- paddingX;
mCoreLayoutParams.y = mSensorProps.sensorLocationX - mSensorProps.sensorRadius
@@ -651,6 +636,7 @@
default:
// Do nothing to stay in portrait mode.
+ // Keyguard is always in portrait mode.
}
// avoid announcing window title
mCoreLayoutParams.accessibilityTitle = " ";
@@ -688,7 +674,8 @@
// This view overlaps the sensor area, so prevent it from being selectable
// during a11y.
if (reason == IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR
- || reason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING) {
+ || reason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING
+ || reason == IUdfpsOverlayController.REASON_AUTH_BP) {
mView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
}
@@ -843,6 +830,9 @@
Log.w(TAG, "Null view in onFingerDown");
return;
}
+ if (!mOnFingerDown) {
+ playStartHaptic();
+ }
mOnFingerDown = true;
mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major);
Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0);
@@ -870,38 +860,6 @@
}
}
- /**
- * get vibration to play given string
- * used for testing purposes (b/185124905)
- */
- public static VibrationEffect getVibration(String effect, VibrationEffect defaultEffect) {
- if (TextUtils.isEmpty(effect)) {
- return defaultEffect;
- }
-
- switch (effect.toLowerCase()) {
- case "click":
- return EFFECT_CLICK;
- case "heavy":
- return EFFECT_HEAVY;
- case "texture_tick":
- return EFFECT_TEXTURE_TICK;
- case "tick":
- return EFFECT_TICK;
- case "double_tap":
- return EFFECT_DOUBLE_CLICK;
- default:
- try {
- int primitive = Integer.parseInt(effect);
- if (primitive <= PRIMITIVE_LOW_TICK && primitive > -1) {
- return VibrationEffect.startComposition().addPrimitive(primitive).compose();
- }
- } catch (NumberFormatException e) {
- }
- return defaultEffect;
- }
- }
-
private void updateTouchListener() {
if (mView == null) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index e82f648..1316184 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -43,6 +43,7 @@
import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieProperty;
import com.airbnb.lottie.model.KeyPath;
+
/**
* View corresponding with udfps_keyguard_view.xml
*/
@@ -138,9 +139,12 @@
mAodFp.setTranslationX(mBurnInOffsetX);
mAodFp.setTranslationY(mBurnInOffsetY);
mAodFp.setProgress(mBurnInProgress);
+ mAodFp.setAlpha(255 * mInterpolatedDarkAmount);
mLockScreenFp.setTranslationX(mBurnInOffsetX);
mLockScreenFp.setTranslationY(mBurnInOffsetY);
+ mLockScreenFp.setProgress(1f - mInterpolatedDarkAmount);
+ mLockScreenFp.setAlpha((1f - mInterpolatedDarkAmount) * 255);
}
void requestUdfps(boolean request, int color) {
@@ -207,14 +211,6 @@
mHintAnimator.cancel();
mInterpolatedDarkAmount = eased;
updateBurnInOffsets();
- mLockScreenFp.setProgress(1f - mInterpolatedDarkAmount);
- mAodFp.setAlpha(mInterpolatedDarkAmount);
-
- if (linear == 1f) {
- mLockScreenFp.setVisibility(View.INVISIBLE);
- } else {
- mLockScreenFp.setVisibility(View.VISIBLE);
- }
}
void animateHint() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
index 809e7a7..37a6cfa 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -33,7 +33,6 @@
import com.android.systemui.classifier.FalsingDataProvider.SessionListener;
import com.android.systemui.classifier.HistoryTracker.BeliefListener;
import com.android.systemui.dagger.qualifiers.TestHarness;
-import com.android.systemui.dock.DockManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -66,7 +65,6 @@
private static final double FALSE_BELIEF_THRESHOLD = 0.9;
private final FalsingDataProvider mDataProvider;
- private final DockManager mDockManager;
private final SingleTapClassifier mSingleTapClassifier;
private final DoubleTapClassifier mDoubleTapClassifier;
private final HistoryTracker mHistoryTracker;
@@ -173,14 +171,13 @@
@Inject
public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
- DockManager dockManager, MetricsLogger metricsLogger,
+ MetricsLogger metricsLogger,
@Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set<FalsingClassifier> classifiers,
SingleTapClassifier singleTapClassifier, DoubleTapClassifier doubleTapClassifier,
HistoryTracker historyTracker, KeyguardStateController keyguardStateController,
AccessibilityManager accessibilityManager,
@TestHarness boolean testHarness) {
mDataProvider = falsingDataProvider;
- mDockManager = dockManager;
mMetricsLogger = metricsLogger;
mClassifiers = classifiers;
mSingleTapClassifier = singleTapClassifier;
@@ -332,7 +329,7 @@
|| !mKeyguardStateController.isShowing()
|| mTestHarness
|| mDataProvider.isJustUnlockedWithFace()
- || mDockManager.isDocked()
+ || mDataProvider.isDocked()
|| mAccessibilityManager.isEnabled();
}
@@ -400,7 +397,7 @@
ipw.print("mJustUnlockedWithFace=");
ipw.println(mDataProvider.isJustUnlockedWithFace() ? 1 : 0);
ipw.print("isDocked=");
- ipw.println(mDockManager.isDocked() ? 1 : 0);
+ ipw.println(mDataProvider.isDocked() ? 1 : 0);
ipw.print("width=");
ipw.println(mDataProvider.getWidthPixels());
ipw.print("height=");
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
index 9697369..14e5991 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -16,6 +16,8 @@
package com.android.systemui.classifier;
+import static com.android.systemui.dock.DockManager.DockEventListener;
+
import android.hardware.SensorManager;
import android.hardware.biometrics.BiometricSourceType;
import android.util.Log;
@@ -25,9 +27,12 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.sensors.ProximitySensor;
@@ -53,6 +58,8 @@
private final ProximitySensor mProximitySensor;
private final StatusBarStateController mStatusBarStateController;
private final KeyguardStateController mKeyguardStateController;
+ private final BatteryController mBatteryController;
+ private final DockManager mDockManager;
private final DelayableExecutor mMainExecutor;
private final SystemClock mSystemClock;
@@ -89,12 +96,46 @@
}
};
+
+ private final BatteryStateChangeCallback mBatteryListener = new BatteryStateChangeCallback() {
+ @Override
+ public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+ }
+
+ @Override
+ public void onWirelessChargingChanged(boolean isWirelessCharging) {
+ if (isWirelessCharging || mDockManager.isDocked()) {
+ mProximitySensor.pause();
+ } else {
+ mProximitySensor.resume();
+ }
+ }
+ };
+
+ private final DockEventListener mDockEventListener = new DockEventListener() {
+ @Override
+ public void onEvent(int event) {
+ if (event == DockManager.STATE_NONE && !mBatteryController.isWirelessCharging()) {
+ mProximitySensor.resume();
+ } else {
+ mProximitySensor.pause();
+ }
+ }
+ };
+
@Inject
- FalsingCollectorImpl(FalsingDataProvider falsingDataProvider, FalsingManager falsingManager,
- KeyguardUpdateMonitor keyguardUpdateMonitor, HistoryTracker historyTracker,
- ProximitySensor proximitySensor, StatusBarStateController statusBarStateController,
+ FalsingCollectorImpl(
+ FalsingDataProvider falsingDataProvider,
+ FalsingManager falsingManager,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ HistoryTracker historyTracker,
+ ProximitySensor proximitySensor,
+ StatusBarStateController statusBarStateController,
KeyguardStateController keyguardStateController,
- @Main DelayableExecutor mainExecutor, SystemClock systemClock) {
+ BatteryController batteryController,
+ DockManager dockManager,
+ @Main DelayableExecutor mainExecutor,
+ SystemClock systemClock) {
mFalsingDataProvider = falsingDataProvider;
mFalsingManager = falsingManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -102,10 +143,11 @@
mProximitySensor = proximitySensor;
mStatusBarStateController = statusBarStateController;
mKeyguardStateController = keyguardStateController;
+ mBatteryController = batteryController;
+ mDockManager = dockManager;
mMainExecutor = mainExecutor;
mSystemClock = systemClock;
-
mProximitySensor.setTag(PROXIMITY_SENSOR_TAG);
mProximitySensor.setDelay(SensorManager.SENSOR_DELAY_GAME);
@@ -113,6 +155,9 @@
mState = mStatusBarStateController.getState();
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
+
+ mBatteryController.addCallback(mBatteryListener);
+ mDockManager.addListener(mDockEventListener);
}
@Override
@@ -312,6 +357,8 @@
unregisterSensors();
mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
+ mBatteryController.removeCallback(mBatteryListener);
+ mDockManager.removeListener(mDockEventListener);
}
@Override
@@ -351,9 +398,7 @@
}
private void registerSensors() {
- if (!mFalsingDataProvider.isWirelessCharging()) {
- mProximitySensor.register(mSensorEventListener);
- }
+ mProximitySensor.register(mSensorEventListener);
}
private void unregisterSensors() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index 2f688dd..a3ecb0c 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -22,6 +22,7 @@
import android.view.MotionEvent.PointerProperties;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.policy.BatteryController;
import java.util.ArrayList;
@@ -40,7 +41,8 @@
private final int mWidthPixels;
private final int mHeightPixels;
- private final BatteryController mBatteryController;
+ private BatteryController mBatteryController;
+ private final DockManager mDockManager;
private final float mXdpi;
private final float mYdpi;
private final List<SessionListener> mSessionListeners = new ArrayList<>();
@@ -59,12 +61,16 @@
private boolean mJustUnlockedWithFace;
@Inject
- public FalsingDataProvider(DisplayMetrics displayMetrics, BatteryController batteryController) {
+ public FalsingDataProvider(
+ DisplayMetrics displayMetrics,
+ BatteryController batteryController,
+ DockManager dockManager) {
mXdpi = displayMetrics.xdpi;
mYdpi = displayMetrics.ydpi;
mWidthPixels = displayMetrics.widthPixels;
mHeightPixels = displayMetrics.heightPixels;
mBatteryController = batteryController;
+ mDockManager = dockManager;
FalsingClassifier.logInfo("xdpi, ydpi: " + getXdpi() + ", " + getYdpi());
FalsingClassifier.logInfo("width, height: " + getWidthPixels() + ", " + getHeightPixels());
@@ -219,11 +225,6 @@
return mLastMotionEvent.getY() < mFirstRecentMotionEvent.getY();
}
- /** Returns true if phone is being charged without a cable. */
- public boolean isWirelessCharging() {
- return mBatteryController.isWirelessCharging();
- }
-
private void recalculateData() {
if (!mDirty) {
return;
@@ -357,6 +358,11 @@
mJustUnlockedWithFace = justUnlockedWithFace;
}
+ /** Returns true if phone is sitting in a dock or is wirelessly charging. */
+ public boolean isDocked() {
+ return mBatteryController.isWirelessCharging() || mDockManager.isDocked();
+ }
+
/** Implement to be alerted abotu the beginning and ending of falsing tracking. */
public interface SessionListener {
/** Called when the lock screen is shown and falsing-tracking begins. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 75f77bf..c7c2590 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1506,8 +1506,10 @@
return;
}
- // if the keyguard is already showing, don't bother
- if (mKeyguardViewControllerLazy.get().isShowing()) {
+ // if the keyguard is already showing, don't bother. check flags in both files
+ // to account for the hiding animation which results in a delay and discrepancy
+ // between flags
+ if (mShowing && mKeyguardViewControllerLazy.get().isShowing()) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
resetStateLocked();
return;
@@ -2309,7 +2311,6 @@
// only play "unlock" noises if not on a call (since the incall UI
// disables the keyguard)
if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) {
- Log.i("TEST", "playSounds: false");
playSounds(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 902e8c2..15a7083 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -475,6 +475,13 @@
@Nullable
private ActivityLaunchAnimator.Controller buildLaunchAnimatorController(
TransitionLayout player) {
+ if (!(player.getParent() instanceof ViewGroup)) {
+ // TODO(b/192194319): Throw instead of just logging.
+ Log.wtf(TAG, "Skipping player animation as it is not attached to a ViewGroup",
+ new Exception());
+ return null;
+ }
+
// TODO(b/174236650): Make sure that the carousel indicator also fades out.
// TODO(b/174236650): Instrument the animation to measure jank.
return new GhostedViewLaunchAnimatorController(player,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 42ad115..3073f83 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -92,6 +92,7 @@
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.IWindowManager;
+import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -383,6 +384,13 @@
}
@Override
+ public void onTaskbarStatusUpdated(boolean visible, boolean stashed) {
+ mNavigationBarView
+ .getFloatingRotationButton()
+ .onTaskbarStateChanged(visible, stashed);
+ }
+
+ @Override
public void onToggleRecentApps() {
// The same case as onOverviewShown but only for 3-button navigation.
mNavigationBarView.getRotationButtonController().setSkipOverrideUserLockPrefsOnce();
@@ -954,7 +962,7 @@
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, boolean isFullscreen) {
+ @Behavior int behavior, InsetsState requestedState, String packageName) {
if (displayId != mDisplayId) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index ecea082..6344c59 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -17,7 +17,6 @@
package com.android.systemui.navigationbar;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.systemui.shared.recents.utilities.Utilities.isTablet;
@@ -350,7 +349,9 @@
Log.w(TAG, "Cannot get WindowManager.");
return;
}
- final Context context = mContext.createWindowContext(display, TYPE_NAVIGATION_BAR, null);
+ final Context context = isOnDefaultDisplay
+ ? mContext
+ : mContext.createDisplayContext(display);
NavigationBar navBar = new NavigationBar(context,
mWindowManager,
mAssistManagerLazy,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 4816f1c..23c066a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -69,6 +69,7 @@
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.model.SysUiState;
+import com.android.systemui.navigationbar.RotationButton.RotationButtonUpdatesCallback;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
import com.android.systemui.navigationbar.buttons.ContextualButton;
import com.android.systemui.navigationbar.buttons.ContextualButtonGroup;
@@ -275,14 +276,23 @@
false /* inScreen */, false /* useNearestRegion */));
};
- private final Consumer<Boolean> mRotationButtonListener = (visible) -> {
- if (visible) {
- // If the button will actually become visible and the navbar is about to hide,
- // tell the statusbar to keep it around for longer
- mAutoHideController.touchAutoHide();
- }
- notifyActiveTouchRegions();
- };
+ private final RotationButtonUpdatesCallback mRotationButtonListener =
+ new RotationButtonUpdatesCallback() {
+ @Override
+ public void onVisibilityChanged(boolean visible) {
+ if (visible) {
+ // If the button will actually become visible and the navbar is about
+ // to hide, tell the statusbar to keep it around for longer
+ mAutoHideController.touchAutoHide();
+ }
+ notifyActiveTouchRegions();
+ }
+
+ @Override
+ public void onPositionChanged() {
+ notifyActiveTouchRegions();
+ }
+ };
private final Consumer<Boolean> mNavbarOverlayVisibilityChangeCallback = (visible) -> {
if (visible) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java
index e487858..3486c6e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java
@@ -20,12 +20,10 @@
import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
-import java.util.function.Consumer;
-
/** Interface of a rotation button that interacts {@link RotationButtonController}. */
public interface RotationButton {
void setRotationButtonController(RotationButtonController rotationButtonController);
- void setVisibilityChangedCallback(Consumer<Boolean> visibilityChangedCallback);
+ void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback);
View getCurrentView();
boolean show();
boolean hide();
@@ -39,4 +37,12 @@
default boolean acceptRotationProposal() {
return getCurrentView() != null;
}
+
+ /**
+ * Callback for updates provided by a rotation button
+ */
+ interface RotationButtonUpdatesCallback {
+ void onVisibilityChanged(boolean isVisible);
+ void onPositionChanged();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
index a5b7911..196625b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
@@ -46,6 +46,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.navigationbar.RotationButton.RotationButtonUpdatesCallback;
import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.recents.utilities.ViewRippler;
@@ -140,12 +141,12 @@
}
void setRotationButton(RotationButton rotationButton,
- Consumer<Boolean> visibilityChangedCallback) {
+ RotationButtonUpdatesCallback updatesCallback) {
mRotationButton = rotationButton;
mRotationButton.setRotationButtonController(this);
mRotationButton.setOnClickListener(this::onRotateSuggestionClick);
mRotationButton.setOnHoverListener(this::onRotateSuggestionHover);
- mRotationButton.setVisibilityChangedCallback(visibilityChangedCallback);
+ mRotationButton.setUpdatesCallback(updatesCallback);
}
void registerListeners() {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 40afed3..1d44146 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -26,6 +26,7 @@
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
+import android.view.InsetsState;
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.model.SysUiState;
@@ -108,7 +109,7 @@
@Override
public void onSystemBarAttributesChanged(int displayId, int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, int behavior,
- boolean isFullscreen) {
+ InsetsState requestedState, String packageName) {
mOverviewProxyService.onSystemBarAttributesChanged(displayId, behavior);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java
index 6a97a33..ebb67af 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java
@@ -23,10 +23,6 @@
import com.android.systemui.navigationbar.RotationButton;
import com.android.systemui.navigationbar.RotationButtonController;
-import com.android.systemui.navigationbar.buttons.ContextualButton;
-import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
-
-import java.util.function.Consumer;
/** Containing logic for the rotation button in nav bar. */
public class RotationContextButton extends ContextualButton implements RotationButton {
@@ -48,13 +44,10 @@
}
@Override
- public void setVisibilityChangedCallback(Consumer<Boolean> visibilityChangedCallback) {
- setListener(new ContextButtonListener() {
- @Override
- public void onVisibilityChanged(ContextualButton button, boolean visible) {
- if (visibilityChangedCallback != null) {
- visibilityChangedCallback.accept(visible);
- }
+ public void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback) {
+ setListener((button, visible) -> {
+ if (updatesCallback != null) {
+ updatesCallback.onVisibilityChanged(visible);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java
index 61118c5..4605795 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java
@@ -20,48 +20,72 @@
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PixelFormat;
-import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.Surface;
import android.view.View;
+import android.view.ViewGroup;
import android.view.WindowManager;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.widget.FrameLayout;
import com.android.systemui.R;
import com.android.systemui.navigationbar.RotationButton;
import com.android.systemui.navigationbar.RotationButtonController;
import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
import com.android.systemui.navigationbar.buttons.KeyButtonView;
+import com.android.systemui.navigationbar.gestural.FloatingRotationButtonPositionCalculator.Position;
-import java.util.function.Consumer;
-
-/** Containing logic for the rotation button on the physical left bottom corner of the screen. */
+/**
+ * Containing logic for the rotation button on the physical left bottom corner of the screen.
+ */
public class FloatingRotationButton implements RotationButton {
private static final float BACKGROUND_ALPHA = 0.92f;
+ private static final int MARGIN_ANIMATION_DURATION_MILLIS = 300;
- private final Context mContext;
private final WindowManager mWindowManager;
+ private final ViewGroup mKeyButtonContainer;
private final KeyButtonView mKeyButtonView;
- private final int mDiameter;
- private final int mMargin;
+
+ private final int mContainerSize;
+
private KeyButtonDrawable mKeyButtonDrawable;
private boolean mIsShowing;
private boolean mCanShow = true;
+ private int mDisplayRotation;
+
+ private boolean mIsTaskbarVisible = false;
+ private boolean mIsTaskbarStashed = false;
+
+ private final FloatingRotationButtonPositionCalculator mPositionCalculator;
private RotationButtonController mRotationButtonController;
- private Consumer<Boolean> mVisibilityChangedCallback;
+ private RotationButtonUpdatesCallback mUpdatesCallback;
+ private Position mPosition;
public FloatingRotationButton(Context context) {
- mContext = context;
- mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- mKeyButtonView = (KeyButtonView) LayoutInflater.from(mContext).inflate(
+ mWindowManager = context.getSystemService(WindowManager.class);
+ mKeyButtonContainer = (ViewGroup) LayoutInflater.from(context).inflate(
R.layout.rotate_suggestion, null);
+ mKeyButtonView = mKeyButtonContainer.findViewById(R.id.rotate_suggestion);
mKeyButtonView.setVisibility(View.VISIBLE);
- Resources res = mContext.getResources();
- mDiameter = res.getDimensionPixelSize(R.dimen.floating_rotation_button_diameter);
- mMargin = Math.max(res.getDimensionPixelSize(R.dimen.floating_rotation_button_min_margin),
+ Resources res = context.getResources();
+
+ int defaultMargin = Math.max(
+ res.getDimensionPixelSize(R.dimen.floating_rotation_button_min_margin),
res.getDimensionPixelSize(R.dimen.rounded_corner_content_padding));
+
+ int taskbarMarginLeft =
+ res.getDimensionPixelSize(R.dimen.floating_rotation_button_taskbar_left_margin);
+ int taskbarMarginBottom =
+ res.getDimensionPixelSize(R.dimen.floating_rotation_button_taskbar_bottom_margin);
+
+ mPositionCalculator = new FloatingRotationButtonPositionCalculator(defaultMargin,
+ taskbarMarginLeft, taskbarMarginBottom);
+
+ final int diameter = res.getDimensionPixelSize(R.dimen.floating_rotation_button_diameter);
+ mContainerSize = diameter + Math.max(defaultMargin, Math.max(taskbarMarginLeft,
+ taskbarMarginBottom));
}
@Override
@@ -72,8 +96,8 @@
}
@Override
- public void setVisibilityChangedCallback(Consumer<Boolean> visibilityChangedCallback) {
- mVisibilityChangedCallback = visibilityChangedCallback;
+ public void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback) {
+ mUpdatesCallback = updatesCallback;
}
@Override
@@ -86,45 +110,39 @@
if (!mCanShow || mIsShowing) {
return false;
}
+
mIsShowing = true;
int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(mDiameter, mDiameter,
- mMargin, mMargin, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, flags,
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ mContainerSize,
+ mContainerSize,
+ 0, 0, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, flags,
PixelFormat.TRANSLUCENT);
+
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
lp.setTitle("FloatingRotationButton");
lp.setFitInsetsTypes(0 /*types */);
- switch (mWindowManager.getDefaultDisplay().getRotation()) {
- case Surface.ROTATION_0:
- lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
- break;
- case Surface.ROTATION_90:
- lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
- break;
- case Surface.ROTATION_180:
- lp.gravity = Gravity.TOP | Gravity.RIGHT;
- break;
- case Surface.ROTATION_270:
- lp.gravity = Gravity.TOP | Gravity.LEFT;
- break;
- default:
- break;
- }
- mWindowManager.addView(mKeyButtonView, lp);
+
+ mDisplayRotation = mWindowManager.getDefaultDisplay().getRotation();
+ mPosition = mPositionCalculator
+ .calculatePosition(mDisplayRotation, mIsTaskbarVisible, mIsTaskbarStashed);
+
+ lp.gravity = mPosition.getGravity();
+ ((FrameLayout.LayoutParams) mKeyButtonView.getLayoutParams()).gravity =
+ mPosition.getGravity();
+
+ updateTranslation(mPosition, /* animate */ false);
+
+ mWindowManager.addView(mKeyButtonContainer, lp);
if (mKeyButtonDrawable != null && mKeyButtonDrawable.canAnimate()) {
mKeyButtonDrawable.resetAnimation();
mKeyButtonDrawable.startAnimation();
}
- mKeyButtonView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5,
- int i6, int i7) {
- if (mIsShowing && mVisibilityChangedCallback != null) {
- mVisibilityChangedCallback.accept(true);
- }
- mKeyButtonView.removeOnLayoutChangeListener(this);
- }
- });
+
+ if (mUpdatesCallback != null) {
+ mUpdatesCallback.onVisibilityChanged(true);
+ }
+
return true;
}
@@ -133,10 +151,10 @@
if (!mIsShowing) {
return false;
}
- mWindowManager.removeViewImmediate(mKeyButtonView);
+ mWindowManager.removeViewImmediate(mKeyButtonContainer);
mIsShowing = false;
- if (mVisibilityChangedCallback != null) {
- mVisibilityChangedCallback.accept(false);
+ if (mUpdatesCallback != null) {
+ mUpdatesCallback.onVisibilityChanged(false);
}
return true;
}
@@ -183,4 +201,43 @@
hide();
}
}
+
+ public void onTaskbarStateChanged(boolean taskbarVisible, boolean taskbarStashed) {
+ mIsTaskbarVisible = taskbarVisible;
+ mIsTaskbarStashed = taskbarStashed;
+
+ if (!mIsShowing) return;
+
+ final Position newPosition = mPositionCalculator
+ .calculatePosition(mDisplayRotation, mIsTaskbarVisible, mIsTaskbarStashed);
+
+ if (newPosition.getTranslationX() != mPosition.getTranslationX()
+ || newPosition.getTranslationY() != mPosition.getTranslationY()) {
+ updateTranslation(newPosition, /* animate */ true);
+ mPosition = newPosition;
+ }
+ }
+
+ private void updateTranslation(Position position, boolean animate) {
+ final int translationX = position.getTranslationX();
+ final int translationY = position.getTranslationY();
+
+ if (animate) {
+ mKeyButtonView
+ .animate()
+ .translationX(translationX)
+ .translationY(translationY)
+ .setDuration(MARGIN_ANIMATION_DURATION_MILLIS)
+ .setInterpolator(new AccelerateDecelerateInterpolator())
+ .withEndAction(() -> {
+ if (mUpdatesCallback != null && mIsShowing) {
+ mUpdatesCallback.onPositionChanged();
+ }
+ })
+ .start();
+ } else {
+ mKeyButtonView.setTranslationX(translationX);
+ mKeyButtonView.setTranslationY(translationY);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculator.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculator.kt
new file mode 100644
index 0000000..3ce51ad
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculator.kt
@@ -0,0 +1,65 @@
+package com.android.systemui.navigationbar.gestural
+
+import android.view.Gravity
+import android.view.Surface
+
+/**
+ * Calculates gravity and translation that is necessary to display
+ * the button in the correct position based on the current state
+ */
+internal class FloatingRotationButtonPositionCalculator(
+ private val defaultMargin: Int,
+ private val taskbarMarginLeft: Int,
+ private val taskbarMarginBottom: Int
+) {
+
+ fun calculatePosition(
+ currentRotation: Int,
+ taskbarVisible: Boolean,
+ taskbarStashed: Boolean
+ ): Position {
+
+ val isTaskbarSide = currentRotation == Surface.ROTATION_0
+ || currentRotation == Surface.ROTATION_90
+ val useTaskbarMargin = isTaskbarSide && taskbarVisible && !taskbarStashed
+
+ val gravity = resolveGravity(currentRotation)
+
+ val marginLeft = if (useTaskbarMargin) taskbarMarginLeft else defaultMargin
+ val marginBottom = if (useTaskbarMargin) taskbarMarginBottom else defaultMargin
+
+ val translationX =
+ if (gravity and Gravity.RIGHT == Gravity.RIGHT) {
+ -marginLeft
+ } else {
+ marginLeft
+ }
+ val translationY =
+ if (gravity and Gravity.BOTTOM == Gravity.BOTTOM) {
+ -marginBottom
+ } else {
+ marginBottom
+ }
+
+ return Position(
+ gravity = gravity,
+ translationX = translationX,
+ translationY = translationY
+ )
+ }
+
+ data class Position(
+ val gravity: Int,
+ val translationX: Int,
+ val translationY: Int
+ )
+
+ private fun resolveGravity(rotation: Int): Int =
+ when (rotation) {
+ Surface.ROTATION_0 -> Gravity.BOTTOM or Gravity.LEFT
+ Surface.ROTATION_90 -> Gravity.BOTTOM or Gravity.RIGHT
+ Surface.ROTATION_180 -> Gravity.TOP or Gravity.RIGHT
+ Surface.ROTATION_270 -> Gravity.TOP or Gravity.LEFT
+ else -> throw IllegalArgumentException("Invalid rotation $rotation")
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
index 335ebca..a16b92f 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
@@ -47,6 +47,7 @@
import android.graphics.Bitmap;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
+import android.graphics.ImageDecoder;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.graphics.text.LineBreaker;
@@ -59,6 +60,7 @@
import android.util.IconDrawableFactory;
import android.util.Log;
import android.util.Pair;
+import android.util.Size;
import android.util.SizeF;
import android.util.TypedValue;
import android.view.Gravity;
@@ -79,6 +81,7 @@
import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
import com.android.systemui.people.widget.PeopleTileKey;
+import java.io.IOException;
import java.text.NumberFormat;
import java.time.Duration;
import java.util.ArrayList;
@@ -178,6 +181,7 @@
private int mWidth;
private int mHeight;
private int mLayoutSize;
+ private boolean mIsLeftToRight;
private Locale mLocale;
private NumberFormat mIntegerFormat;
@@ -192,6 +196,8 @@
mWidth = width;
mHeight = height;
mLayoutSize = getLayoutSize();
+ mIsLeftToRight = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault())
+ == View.LAYOUT_DIRECTION_LTR;
}
/**
@@ -656,7 +662,7 @@
private RemoteViews createMissedCallRemoteViews() {
RemoteViews views = setViewForContentLayout(new RemoteViews(mContext.getPackageName(),
getLayoutForContent()));
- views.setViewVisibility(R.id.predefined_icon, View.VISIBLE);
+ setPredefinedIconVisible(views);
views.setViewVisibility(R.id.text_content, View.VISIBLE);
views.setViewVisibility(R.id.messages_count, View.GONE);
setMaxLines(views, false);
@@ -675,19 +681,39 @@
return views;
}
+ private void setPredefinedIconVisible(RemoteViews views) {
+ views.setViewVisibility(R.id.predefined_icon, View.VISIBLE);
+ if (mLayoutSize == LAYOUT_MEDIUM) {
+ int endPadding = mContext.getResources().getDimensionPixelSize(
+ R.dimen.before_predefined_icon_padding);
+ views.setViewPadding(R.id.name, mIsLeftToRight ? 0 : endPadding, 0,
+ mIsLeftToRight ? endPadding : 0,
+ 0);
+ }
+ }
+
private RemoteViews createNotificationRemoteViews() {
RemoteViews views = setViewForContentLayout(new RemoteViews(mContext.getPackageName(),
getLayoutForNotificationContent()));
CharSequence sender = mTile.getNotificationSender();
- Uri image = mTile.getNotificationDataUri();
- if (image != null) {
- // TODO: Use NotificationInlineImageCache
- views.setImageViewUri(R.id.image, image);
+ Uri imageUri = mTile.getNotificationDataUri();
+ if (imageUri != null) {
String newImageDescription = mContext.getString(
R.string.new_notification_image_content_description, mTile.getUserName());
views.setContentDescription(R.id.image, newImageDescription);
views.setViewVisibility(R.id.image, View.VISIBLE);
views.setViewVisibility(R.id.text_content, View.GONE);
+ try {
+ Drawable drawable = resolveImage(imageUri, mContext);
+ Bitmap bitmap = convertDrawableToBitmap(drawable);
+ views.setImageViewBitmap(R.id.image, bitmap);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not decode image: " + e);
+ // If we couldn't load the image, show text that we have a new image.
+ views.setTextViewText(R.id.text_content, newImageDescription);
+ views.setViewVisibility(R.id.text_content, View.VISIBLE);
+ views.setViewVisibility(R.id.image, View.GONE);
+ }
} else {
setMaxLines(views, !TextUtils.isEmpty(sender));
CharSequence content = mTile.getNotificationContent();
@@ -705,6 +731,13 @@
views.setImageViewResource(R.id.predefined_icon, R.drawable.ic_message);
}
if (mTile.getMessagesCount() > 1) {
+ if (mLayoutSize == LAYOUT_MEDIUM) {
+ int endPadding = mContext.getResources().getDimensionPixelSize(
+ R.dimen.before_messages_count_padding);
+ views.setViewPadding(R.id.name, mIsLeftToRight ? 0 : endPadding, 0,
+ mIsLeftToRight ? endPadding : 0,
+ 0);
+ }
views.setViewVisibility(R.id.messages_count, View.VISIBLE);
views.setTextViewText(R.id.messages_count,
getMessagesCountText(mTile.getMessagesCount()));
@@ -722,6 +755,40 @@
return views;
}
+ private Drawable resolveImage(Uri uri, Context context) throws IOException {
+ final ImageDecoder.Source source =
+ ImageDecoder.createSource(context.getContentResolver(), uri);
+ final Drawable drawable =
+ ImageDecoder.decodeDrawable(source, (decoder, info, s) -> {
+ onHeaderDecoded(decoder, info, s);
+ });
+ return drawable;
+ }
+
+ private static int getPowerOfTwoForSampleRatio(double ratio) {
+ final int k = Integer.highestOneBit((int) Math.floor(ratio));
+ return Math.max(1, k);
+ }
+
+ private void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info,
+ ImageDecoder.Source source) {
+ int widthInPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mWidth,
+ mContext.getResources().getDisplayMetrics());
+ int heightInPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mHeight,
+ mContext.getResources().getDisplayMetrics());
+ int maxIconSizeInPx = Math.max(widthInPx, heightInPx);
+ int minDimen = (int) (1.5 * Math.min(widthInPx, heightInPx));
+ if (minDimen < maxIconSizeInPx) {
+ maxIconSizeInPx = minDimen;
+ }
+ final Size size = info.getSize();
+ final int originalSize = Math.max(size.getHeight(), size.getWidth());
+ final double ratio = (originalSize > maxIconSizeInPx)
+ ? originalSize * 1f / maxIconSizeInPx
+ : 1.0;
+ decoder.setTargetSampleSize(getPowerOfTwoForSampleRatio(ratio));
+ }
+
private void setContentDescriptionForNotificationTextContent(RemoteViews views,
CharSequence content, CharSequence sender) {
String newTextDescriptionWithNotificationContent = mContext.getString(
@@ -757,7 +824,7 @@
if (TextUtils.isEmpty(statusText)) {
statusText = getStatusTextByType(status.getActivity());
}
- views.setViewVisibility(R.id.predefined_icon, View.VISIBLE);
+ setPredefinedIconVisible(views);
views.setTextViewText(R.id.text_content, statusText);
if (status.getActivity() == ACTIVITY_BIRTHDAY
@@ -867,13 +934,11 @@
* on the status layouts compared to all other layouts.
*/
private void setAvailabilityDotPadding(RemoteViews views, int resId) {
- boolean isLeftToRight = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault())
- == View.LAYOUT_DIRECTION_LTR;
int startPadding = mContext.getResources().getDimensionPixelSize(resId);
int bottomPadding = mContext.getResources().getDimensionPixelSize(
R.dimen.medium_content_padding_above_name);
views.setViewPadding(R.id.medium_content,
- isLeftToRight ? startPadding : 0, 0, isLeftToRight ? 0 : startPadding,
+ mIsLeftToRight ? startPadding : 0, 0, mIsLeftToRight ? 0 : startPadding,
bottomPadding);
}
@@ -1071,6 +1136,7 @@
views.setViewPadding(R.id.content, horizontalPadding, verticalPadding,
horizontalPadding,
verticalPadding);
+ views.setViewPadding(R.id.name, 0, 0, 0, 0);
// Expand the name font on medium if there's space.
int heightRequiredForMaxContentText = (int) (mContext.getResources().getDimension(
R.dimen.medium_height_for_max_name_text_size) / mDensity);
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 3320fbd..9859034 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -375,7 +375,7 @@
widgetSp.getInt(USER_ID, INVALID_USER_ID),
widgetSp.getString(PACKAGE_NAME, EMPTY_STRING));
- return getTileFromPersistentStorage(key, appWidgetId);
+ return getTileFromPersistentStorage(key, appWidgetId, /* supplementFromStorage= */ true);
}
/**
@@ -383,7 +383,8 @@
* If a {@link PeopleTileKey} is not provided, fetch one from {@link SharedPreferences}.
*/
@Nullable
- public PeopleSpaceTile getTileFromPersistentStorage(PeopleTileKey key, int appWidgetId) throws
+ public PeopleSpaceTile getTileFromPersistentStorage(PeopleTileKey key, int appWidgetId,
+ boolean supplementFromStorage) throws
PackageManager.NameNotFoundException {
if (!PeopleTileKey.isValid(key)) {
Log.e(TAG, "PeopleTileKey invalid: " + key.toString());
@@ -412,7 +413,8 @@
// Supplement with our storage.
String contactUri = mSharedPrefs.getString(String.valueOf(appWidgetId), null);
- if (contactUri != null && storedTile.build().getContactUri() == null) {
+ if (supplementFromStorage && contactUri != null
+ && storedTile.build().getContactUri() == null) {
if (DEBUG) Log.d(TAG, "Restore contact uri from storage: " + contactUri);
storedTile.setContactUri(Uri.parse(contactUri));
}
@@ -811,7 +813,8 @@
if (DEBUG) Log.d(TAG, "addNewWidget called with key for appWidgetId: " + appWidgetId);
PeopleSpaceTile tile = null;
try {
- tile = getTileFromPersistentStorage(key, appWidgetId);
+ tile = getTileFromPersistentStorage(key, appWidgetId, /* supplementFromStorage= */
+ false);
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Cannot add widget since app was uninstalled");
return;
@@ -850,7 +853,9 @@
} catch (Exception e) {
Log.w(TAG, "Exception caching shortcut:" + e);
}
- updateAppWidgetOptionsAndView(appWidgetId, tile);
+ PeopleSpaceTile finalTile = tile;
+ mBgExecutor.execute(
+ () -> updateAppWidgetOptionsAndView(appWidgetId, finalTile));
}
/** Registers a conversation listener for {@code appWidgetId} if not already registered. */
@@ -1071,7 +1076,7 @@
return;
}
for (int appWidgetId : appWidgetIds) {
- if (DEBUG) Log.d(TAG, "Updating widget from broadcast, widget id: " + appWidgetId);
+ if (DEBUG) Log.d(TAG, "Updating widget from broadcast, widget id: " + appWidgetId);
PeopleSpaceTile existingTile = null;
PeopleSpaceTile updatedTile = null;
try {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index e9b19e5..eeae652 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -160,8 +160,8 @@
QuickStatusBarHeaderController quickStatusBarHeaderController) {
mQSPanelContainer.setPaddingRelative(
getPaddingStart(),
- mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.quick_qs_offset_height),
+ mContext.getResources()
+ .getDimensionPixelSize(R.dimen.qs_header_system_icons_area_height),
getPaddingEnd(),
getPaddingBottom()
);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 1d6c7c9..929927e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -212,6 +212,11 @@
Dependency.get(CommandQueue.class).animateCollapsePanels();
mTriggeredExpand = false;
}
+ // Always animate on close, even if the last opened detail adapter had shouldAnimate()
+ // return false. This is necessary to avoid a race condition which could leave the
+ // keyguard in a bad state where QS remains visible underneath the notifications, clock,
+ // and status area.
+ mShouldAnimate = true;
}
boolean visibleDiff = wasShowingDetail != showingDetail;
@@ -245,10 +250,15 @@
mClosingDetail = true;
mDetailAdapter = null;
listener = mTeardownDetailWhenDone;
- mHeader.setVisibility(View.VISIBLE);
- mFooter.setVisibility(View.VISIBLE);
- mQsPanelController.setGridContentVisibility(true);
- mQsPanelCallback.onScanStateChanged(false);
+ // Only update visibility if already expanded. Otherwise, a race condition can cause the
+ // keyguard to enter a bad state where the QS tiles are displayed underneath the
+ // notifications, clock, and status area.
+ if (mQsPanelController.isExpanded()) {
+ mHeader.setVisibility(View.VISIBLE);
+ mFooter.setVisibility(View.VISIBLE);
+ mQsPanelController.setGridContentVisibility(true);
+ mQsPanelCallback.onScanStateChanged(false);
+ }
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
animateDetailVisibleDiff(x, y, visibleDiff, listener);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 03a2c84..cd7ad16 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -57,9 +57,8 @@
protected QuickQSPanel mHeaderQsPanel;
private View mDatePrivacyView;
- private View mDateView;
private View mSecurityHeaderView;
- private View mClockIconsView;
+ private View mStatusIconsView;
private View mContainer;
private View mQSCarriers;
@@ -82,7 +81,6 @@
private int mWaterfallTopInset;
private int mCutOutPaddingLeft;
private int mCutOutPaddingRight;
- private float mViewAlpha = 1.0f;
private float mKeyguardExpansionFraction;
private int mTextColorPrimary = Color.TRANSPARENT;
private int mTopViewMeasureHeight;
@@ -115,12 +113,11 @@
mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
mDatePrivacyView = findViewById(R.id.quick_status_bar_date_privacy);
- mClockIconsView = findViewById(R.id.quick_qs_status_icons);
+ mStatusIconsView = findViewById(R.id.quick_qs_status_icons);
mQSCarriers = findViewById(R.id.carrier_group);
mContainer = findViewById(R.id.qs_container);
mIconContainer = findViewById(R.id.statusIcons);
mPrivacyChip = findViewById(R.id.privacy_chip);
- mDateView = findViewById(R.id.date);
mSecurityHeaderView = findViewById(R.id.header_text_container);
mClockIconsSeparator = findViewById(R.id.separator);
mRightLayout = findViewById(R.id.rightLayout);
@@ -161,10 +158,6 @@
updateAnimators();
}
- public QuickQSPanel getHeaderQsPanel() {
- return mHeaderQsPanel;
- }
-
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -201,6 +194,11 @@
void updateResources() {
Resources resources = mContext.getResources();
+ // status bar is already displayed out of QS in split shade
+ boolean shouldUseSplitShade =
+ resources.getBoolean(R.bool.config_use_split_notification_shade);
+ mStatusIconsView.setVisibility(shouldUseSplitShade ? View.GONE : View.VISIBLE);
+ mDatePrivacyView.setVisibility(shouldUseSplitShade ? View.GONE : View.VISIBLE);
mRoundedCornerPadding = resources.getDimensionPixelSize(
R.dimen.rounded_corner_content_padding);
@@ -212,13 +210,13 @@
Math.max(qsOffsetHeight, mDatePrivacyView.getMinimumHeight());
mDatePrivacyView.setLayoutParams(mDatePrivacyView.getLayoutParams());
- mClockIconsView.getLayoutParams().height =
- Math.max(qsOffsetHeight, mClockIconsView.getMinimumHeight());
- mClockIconsView.setLayoutParams(mClockIconsView.getLayoutParams());
+ mStatusIconsView.getLayoutParams().height =
+ Math.max(qsOffsetHeight, mStatusIconsView.getMinimumHeight());
+ mStatusIconsView.setLayoutParams(mStatusIconsView.getLayoutParams());
ViewGroup.LayoutParams lp = getLayoutParams();
if (mQsDisabled) {
- lp.height = mClockIconsView.getLayoutParams().height;
+ lp.height = mStatusIconsView.getLayoutParams().height;
} else {
lp.height = WRAP_CONTENT;
}
@@ -364,7 +362,7 @@
if (disabled == mQsDisabled) return;
mQsDisabled = disabled;
mHeaderQsPanel.setDisabledByPolicy(disabled);
- mClockIconsView.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
+ mStatusIconsView.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
updateResources();
}
@@ -378,7 +376,7 @@
StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner(
cutout, cornerCutoutPadding, -1);
mDatePrivacyView.setPadding(padding.first, 0, padding.second, 0);
- mClockIconsView.setPadding(padding.first, 0, padding.second, 0);
+ mStatusIconsView.setPadding(padding.first, 0, padding.second, 0);
LinearLayout.LayoutParams datePrivacySeparatorLayoutParams =
(LinearLayout.LayoutParams) mDatePrivacySeparator.getLayoutParams();
LinearLayout.LayoutParams mClockIconsSeparatorLayoutParams =
@@ -440,7 +438,7 @@
private void updateHeadersPadding() {
setContentMargins(mDatePrivacyView, 0, 0);
- setContentMargins(mClockIconsView, 0, 0);
+ setContentMargins(mStatusIconsView, 0, 0);
int paddingLeft = 0;
int paddingRight = 0;
@@ -466,7 +464,7 @@
mWaterfallTopInset,
paddingRight,
0);
- mClockIconsView.setPadding(paddingLeft,
+ mStatusIconsView.setPadding(paddingLeft,
mWaterfallTopInset,
paddingRight,
0);
@@ -493,7 +491,7 @@
* @param scrollY the scroll of the QSPanel container
*/
public void setExpandedScrollAmount(int scrollY) {
- mClockIconsView.setScrollY(scrollY);
+ mStatusIconsView.setScrollY(scrollY);
mDatePrivacyView.setScrollY(scrollY);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 7518b20..d33982c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -84,8 +84,8 @@
void updateResources() {
LayoutParams lp = (LayoutParams) mTransparentView.getLayoutParams();
- lp.height = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.quick_qs_offset_height);
+ lp.height = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.qs_header_system_icons_area_height);
mTransparentView.setLayoutParams(lp);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 5325943..da9d888 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -110,6 +110,7 @@
import java.util.List;
import java.util.Optional;
import java.util.function.BiConsumer;
+import java.util.function.Supplier;
import javax.inject.Inject;
@@ -172,55 +173,34 @@
public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@Override
public void startScreenPinning(int taskId) {
- if (!verifyCaller("startScreenPinning")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> {
+ verifyCallerAndClearCallingIdentityPostMain("startScreenPinning", () ->
mStatusBarOptionalLazy.ifPresent(
statusBarLazy -> statusBarLazy.get().showScreenPinningRequest(taskId,
- false /* allowCancel */));
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ false /* allowCancel */)));
}
@Override
public void stopScreenPinning() {
- if (!verifyCaller("stopScreenPinning")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> {
- try {
- ActivityTaskManager.getService().stopSystemLockTaskMode();
- } catch (RemoteException e) {
- Log.e(TAG_OPS, "Failed to stop screen pinning");
- }
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("stopScreenPinning", () -> {
+ try {
+ ActivityTaskManager.getService().stopSystemLockTaskMode();
+ } catch (RemoteException e) {
+ Log.e(TAG_OPS, "Failed to stop screen pinning");
+ }
+ });
}
// TODO: change the method signature to use (boolean inputFocusTransferStarted)
@Override
public void onStatusBarMotionEvent(MotionEvent event) {
- if (!verifyCaller("onStatusBarMotionEvent")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
+ verifyCallerAndClearCallingIdentity("onStatusBarMotionEvent", () -> {
// TODO move this logic to message queue
mStatusBarOptionalLazy.ifPresent(statusBarLazy -> {
StatusBar statusBar = statusBarLazy.get();
if (event.getActionMasked() == ACTION_DOWN) {
statusBar.getPanelController().startExpandLatencyTracking();
}
- mHandler.post(()-> {
+ mHandler.post(() -> {
int action = event.getActionMasked();
if (action == ACTION_DOWN) {
mInputFocusTransferStarted = true;
@@ -232,50 +212,38 @@
}
if (action == ACTION_UP || action == ACTION_CANCEL) {
mInputFocusTransferStarted = false;
+ float velocity = (event.getY() - mInputFocusTransferStartY)
+ / (event.getEventTime() - mInputFocusTransferStartMillis);
statusBar.onInputFocusTransfer(mInputFocusTransferStarted,
action == ACTION_CANCEL,
- (event.getY() - mInputFocusTransferStartY)
- / (event.getEventTime() - mInputFocusTransferStartMillis));
+ velocity);
}
event.recycle();
});
});
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ });
}
@Override
public void onBackPressed() throws RemoteException {
- if (!verifyCaller("onBackPressed")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> {
- sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
- sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
+ verifyCallerAndClearCallingIdentityPostMain("onBackPressed", () -> {
+ sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
+ sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
- notifyBackAction(true, -1, -1, true, false);
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ notifyBackAction(true, -1, -1, true, false);
+ });
}
@Override
public void setHomeRotationEnabled(boolean enabled) {
- if (!verifyCaller("setHomeRotationEnabled")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> {
- mHandler.post(() -> notifyHomeRotationEnabled(enabled));
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("setHomeRotationEnabled", () ->
+ mHandler.post(() -> notifyHomeRotationEnabled(enabled)));
+ }
+
+ @Override
+ public void notifyTaskbarStatus(boolean visible, boolean stashed) {
+ verifyCallerAndClearCallingIdentityPostMain("notifyTaskbarStatus", () ->
+ onTaskbarStatusUpdated(visible, stashed));
}
private boolean sendEvent(int action, int code) {
@@ -292,124 +260,74 @@
@Override
public void onOverviewShown(boolean fromHome) {
- if (!verifyCaller("onOverviewShown")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> {
- for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
- mConnectionCallbacks.get(i).onOverviewShown(fromHome);
- }
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("onOverviewShown", () -> {
+ for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+ mConnectionCallbacks.get(i).onOverviewShown(fromHome);
+ }
+ });
}
@Override
public Rect getNonMinimizedSplitScreenSecondaryBounds() {
- if (!verifyCaller("getNonMinimizedSplitScreenSecondaryBounds")) {
- return null;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- return mLegacySplitScreenOptional.map(splitScreen ->
- splitScreen.getDividerView().getNonMinimizedSplitScreenSecondaryBounds())
- .orElse(null);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ return verifyCallerAndClearCallingIdentity(
+ "getNonMinimizedSplitScreenSecondaryBounds",
+ () -> mLegacySplitScreenOptional.map(splitScreen ->
+ splitScreen
+ .getDividerView()
+ .getNonMinimizedSplitScreenSecondaryBounds())
+ .orElse(null)
+ );
}
@Override
public void setNavBarButtonAlpha(float alpha, boolean animate) {
- if (!verifyCaller("setNavBarButtonAlpha")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mNavBarButtonAlpha = alpha;
- mHandler.post(() -> notifyNavBarButtonAlphaChanged(alpha, animate));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("setNavBarButtonAlpha", () ->
+ notifyNavBarButtonAlphaChanged(alpha, animate));
}
@Override
public void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
- if (!verifyCaller("onAssistantProgress")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> notifyAssistantProgress(progress));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("onAssistantProgress", () ->
+ notifyAssistantProgress(progress));
}
@Override
public void onAssistantGestureCompletion(float velocity) {
- if (!verifyCaller("onAssistantGestureCompletion")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> notifyAssistantGestureCompletion(velocity));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("onAssistantGestureCompletion", () ->
+ notifyAssistantGestureCompletion(velocity));
}
@Override
public void startAssistant(Bundle bundle) {
- if (!verifyCaller("startAssistant")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> notifyStartAssistant(bundle));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("startAssistant", () ->
+ notifyStartAssistant(bundle));
}
@Override
public void notifyAccessibilityButtonClicked(int displayId) {
- if (!verifyCaller("notifyAccessibilityButtonClicked")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- AccessibilityManager.getInstance(mContext)
- .notifyAccessibilityButtonClicked(displayId);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonClicked", () ->
+ AccessibilityManager.getInstance(mContext)
+ .notifyAccessibilityButtonClicked(displayId));
}
@Override
public void notifyAccessibilityButtonLongClicked() {
- if (!verifyCaller("notifyAccessibilityButtonLongClicked")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- final Intent intent =
- new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
- final String chooserClassName = AccessibilityButtonChooserActivity.class.getName();
- intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonLongClicked",
+ () -> {
+ final Intent intent =
+ new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
+ final String chooserClassName = AccessibilityButtonChooserActivity
+ .class.getName();
+ intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName);
+ intent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ });
}
@Override
public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen,
- Insets visibleInsets, int taskId) {
+ Insets visibleInsets, int taskId) {
// Deprecated
}
@@ -421,43 +339,22 @@
@Override
public void notifySwipeToHomeFinished() {
- if (!verifyCaller("notifySwipeToHomeFinished")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mPipOptional.ifPresent(
- pip -> pip.setPinnedStackAnimationType(
- PipAnimationController.ANIM_TYPE_ALPHA));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentity("notifySwipeToHomeFinished", () ->
+ mPipOptional.ifPresent(
+ pip -> pip.setPinnedStackAnimationType(
+ PipAnimationController.ANIM_TYPE_ALPHA)));
}
@Override
public void notifySwipeUpGestureStarted() {
- if (!verifyCaller("notifySwipeUpGestureStarted")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> notifySwipeUpGestureStartedInternal());
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("notifySwipeUpGestureStarted", () ->
+ notifySwipeUpGestureStartedInternal());
}
@Override
public void notifyPrioritizedRotation(@Surface.Rotation int rotation) {
- if (!verifyCaller("notifyPrioritizedRotation")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> notifyPrioritizedRotationInternal(rotation));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("notifyPrioritizedRotation", () ->
+ notifyPrioritizedRotationInternal(rotation));
}
@Override
@@ -477,15 +374,8 @@
@Override
public void expandNotificationPanel() {
- if (!verifyCaller("expandNotificationPanel")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentity("expandNotificationPanel",
+ () -> mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN));
}
private boolean verifyCaller(String reason) {
@@ -497,6 +387,29 @@
}
return true;
}
+
+ private <T> T verifyCallerAndClearCallingIdentity(String reason, Supplier<T> supplier) {
+ if (!verifyCaller(reason)) {
+ return null;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return supplier.get();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private void verifyCallerAndClearCallingIdentity(String reason, Runnable runnable) {
+ verifyCallerAndClearCallingIdentity(reason, () -> {
+ runnable.run();
+ return null;
+ });
+ }
+
+ private void verifyCallerAndClearCallingIdentityPostMain(String reason, Runnable runnable) {
+ verifyCallerAndClearCallingIdentity(reason, () -> mHandler.post(runnable));
+ }
};
private final Runnable mDeferredConnectionCallback = () -> {
@@ -883,6 +796,12 @@
}
}
+ private void onTaskbarStatusUpdated(boolean visible, boolean stashed) {
+ for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+ mConnectionCallbacks.get(i).onTaskbarStatusUpdated(visible, stashed);
+ }
+ }
+
private void notifyConnectionChanged() {
for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
@@ -1049,6 +968,7 @@
/** Notify changes in the nav bar button alpha */
default void onNavBarButtonAlphaChanged(float alpha, boolean animate) {}
default void onHomeRotationEnabled(boolean enabled) {}
+ default void onTaskbarStatusUpdated(boolean visible, boolean stashed) {}
default void onSystemUiStateChanged(int sysuiStateFlags) {}
default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {}
default void onAssistantGestureCompletion(float velocity) {}
diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
index ef18df5..f0fb5eb 100644
--- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
@@ -17,6 +17,7 @@
package com.android.systemui.sensorprivacy
import android.content.DialogInterface
+import android.content.Intent
import android.content.Intent.EXTRA_PACKAGE_NAME
import android.content.pm.PackageManager
import android.content.res.Resources
@@ -178,7 +179,7 @@
override fun onStart() {
super.onStart()
- sensorPrivacyController.suppressSensorPrivacyReminders(sensorUsePackageName, true)
+ setSuppressed(true)
unsuppressImmediately = false
}
@@ -218,12 +219,10 @@
super.onStop()
if (unsuppressImmediately) {
- sensorPrivacyController
- .suppressSensorPrivacyReminders(sensorUsePackageName, false)
+ setSuppressed(false)
} else {
bgHandler.postDelayed({
- sensorPrivacyController
- .suppressSensorPrivacyReminders(sensorUsePackageName, false)
+ setSuppressed(false)
}, SUPPRESS_REMINDERS_REMOVAL_DELAY_MILLIS)
}
}
@@ -237,6 +236,11 @@
// do not allow backing out
}
+ override fun onNewIntent(intent: Intent?) {
+ setIntent(intent)
+ recreate()
+ }
+
private fun disableSensorPrivacy() {
if (sensor == ALL_SENSORS) {
sensorPrivacyController.setSensorBlocked(DIALOG, MICROPHONE, false)
@@ -247,4 +251,16 @@
unsuppressImmediately = true
setResult(RESULT_OK)
}
+
+ private fun setSuppressed(suppressed: Boolean) {
+ if (sensor == ALL_SENSORS) {
+ sensorPrivacyController
+ .suppressSensorPrivacyReminders(MICROPHONE, suppressed)
+ sensorPrivacyController
+ .suppressSensorPrivacyReminders(CAMERA, suppressed)
+ } else {
+ sensorPrivacyController
+ .suppressSensorPrivacyReminders(sensor, suppressed)
+ }
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 8e52b0d..c7f8dcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -50,6 +50,7 @@
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
+import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -337,7 +338,7 @@
*/
default void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, boolean isFullscreen) { }
+ @Behavior int behavior, InsetsState requestedState, String packageName) { }
/**
* @see IStatusBar#showTransient(int, int[]).
@@ -996,7 +997,7 @@
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, boolean isFullscreen) {
+ @Behavior int behavior, InsetsState requestedState, String packageName) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
args.argi1 = displayId;
@@ -1004,7 +1005,8 @@
args.argi3 = navbarColorManagedByIme ? 1 : 0;
args.arg1 = appearanceRegions;
args.argi4 = behavior;
- args.argi5 = isFullscreen ? 1 : 0;
+ args.arg2 = requestedState;
+ args.arg3 = packageName;
mHandler.obtainMessage(MSG_SYSTEM_BAR_CHANGED, args).sendToTarget();
}
}
@@ -1387,7 +1389,7 @@
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onSystemBarAttributesChanged(args.argi1, args.argi2,
(AppearanceRegion[]) args.arg1, args.argi3 == 1, args.argi4,
- args.argi5 == 1);
+ (InsetsState) args.arg2, (String) args.arg3);
}
args.recycle();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index a00d014..5302188 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -416,10 +416,12 @@
return mIcon.icon;
}
- private Drawable getIcon(StatusBarIcon icon) {
- Context notifContext = mNotification != null ?
- mNotification.getPackageContext(getContext()) : getContext();
- return getIcon(getContext(), notifContext, icon);
+ Drawable getIcon(StatusBarIcon icon) {
+ Context notifContext = getContext();
+ if (mNotification != null) {
+ notifContext = mNotification.getPackageContext(getContext());
+ }
+ return getIcon(getContext(), notifContext != null ? notifContext : getContext(), icon);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 0725bf9..d4f5bd2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -16,6 +16,10 @@
package com.android.systemui.statusbar;
+import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
+import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
+
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_TO_AOD;
@@ -23,10 +27,16 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
+import android.os.SystemProperties;
import android.text.format.DateFormat;
import android.util.FloatProperty;
import android.util.Log;
+import android.view.InsetsFlags;
+import android.view.InsetsState;
import android.view.View;
+import android.view.ViewDebug;
+import android.view.WindowInsetsController.Appearance;
+import android.view.WindowInsetsController.Behavior;
import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
@@ -56,6 +66,9 @@
public class StatusBarStateControllerImpl implements SysuiStatusBarStateController,
CallbackController<StateListener>, Dumpable {
private static final String TAG = "SbStateController";
+ private static final boolean DEBUG_IMMERSIVE_APPS =
+ SystemProperties.getBoolean("persist.debug.immersive_apps", false);
+
// Must be a power of 2
private static final int HISTORY_SIZE = 32;
@@ -420,7 +433,10 @@
}
@Override
- public void setFullscreenState(boolean isFullscreen) {
+ public void setSystemBarAttributes(@Appearance int appearance, @Behavior int behavior,
+ InsetsState requestedState, String packageName) {
+ boolean isFullscreen = !requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR)
+ || !requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR);
if (mIsFullscreen != isFullscreen) {
mIsFullscreen = isFullscreen;
synchronized (mListeners) {
@@ -429,6 +445,19 @@
}
}
}
+
+ // TODO (b/190543382): Finish the logging logic.
+ // This section can be removed if we don't need to print it on logcat.
+ if (DEBUG_IMMERSIVE_APPS) {
+ boolean dim = (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0;
+ String behaviorName = ViewDebug.flagsToString(InsetsFlags.class, "behavior", behavior);
+ String requestedVisibilityString = requestedState.toSourceVisibilityString();
+ if (requestedVisibilityString.isEmpty()) {
+ requestedVisibilityString = "none";
+ }
+ Log.d(TAG, packageName + " dim=" + dim + " behavior=" + behaviorName
+ + " requested visibilities: " + requestedVisibilityString);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
index 2520050..0bbae2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
@@ -19,7 +19,10 @@
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
+import android.view.InsetsState;
import android.view.View;
+import android.view.WindowInsetsController.Appearance;
+import android.view.WindowInsetsController.Behavior;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -155,9 +158,10 @@
boolean isKeyguardRequested();
/**
- * Set the fullscreen state
+ * Set the system bar attributes
*/
- void setFullscreenState(boolean isFullscreen);
+ void setSystemBarAttributes(@Appearance int appearance, @Behavior int behavior,
+ InsetsState requestedState, String packageName);
/**
* Set pulsing
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 4bd2716..d9484fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -89,7 +89,6 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
import com.android.systemui.statusbar.notification.FakeShadowView;
-import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.ShadeViewRefactor;
@@ -155,7 +154,7 @@
* gap is drawn between them). In this case we don't want to round their corners.
*/
private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1;
- private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider;
+ private boolean mKeyguardBypassEnabled;
private ExpandHelper mExpandHelper;
private NotificationSwipeHelper mSwipeHelper;
@@ -212,7 +211,6 @@
private GroupMembershipManager mGroupMembershipManager;
private GroupExpansionManager mGroupExpansionManager;
- private NotificationActivityStarter mNotificationActivityStarter;
private HashSet<ExpandableView> mChildrenToAddAnimated = new HashSet<>();
private ArrayList<View> mAddedHeadsUpChildren = new ArrayList<>();
private ArrayList<ExpandableView> mChildrenToRemoveAnimated = new ArrayList<>();
@@ -565,6 +563,9 @@
}
};
+ @Nullable
+ private OnClickListener mManageButtonClickListener;
+
@Inject
public NotificationStackScrollLayout(
@Named(VIEW_CONTEXT) Context context,
@@ -651,12 +652,20 @@
}
/**
+ * Sets whether keyguard bypass is enabled. If true, this layout will be rendered in bypass
+ * mode when it is on the keyguard.
+ */
+ public void setKeyguardBypassEnabled(boolean isEnabled) {
+ mKeyguardBypassEnabled = isEnabled;
+ }
+
+ /**
* @return the height at which we will wake up when pulsing
*/
public float getWakeUpHeight() {
ExpandableView firstChild = getFirstChildWithBackground();
if (firstChild != null) {
- if (mKeyguardBypassEnabledProvider.getBypassEnabled()) {
+ if (mKeyguardBypassEnabled) {
return firstChild.getHeadsUpHeightWithoutHeader();
} else {
return firstChild.getCollapsedHeight();
@@ -794,7 +803,7 @@
}
}
boolean shouldDrawBackground;
- if (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()) {
+ if (mKeyguardBypassEnabled && onKeyguard()) {
shouldDrawBackground = isPulseExpanding();
} else {
shouldDrawBackground = !mAmbientState.isDozing() || anySectionHasVisibleChild;
@@ -909,15 +918,12 @@
}
private void reinitView() {
- initView(getContext(), mKeyguardBypassEnabledProvider, mSwipeHelper);
+ initView(getContext(), mSwipeHelper);
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void initView(Context context,
- KeyguardBypassEnabledProvider keyguardBypassEnabledProvider,
- NotificationSwipeHelper swipeHelper) {
+ void initView(Context context, NotificationSwipeHelper swipeHelper) {
mScroller = new OverScroller(getContext());
- mKeyguardBypassEnabledProvider = keyguardBypassEnabledProvider;
mSwipeHelper = swipeHelper;
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
@@ -1357,7 +1363,7 @@
private void notifyAppearChangedListeners() {
float appear;
float expandAmount;
- if (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()) {
+ if (mKeyguardBypassEnabled && onKeyguard()) {
appear = calculateAppearFractionBypass();
expandAmount = getPulseHeight();
} else {
@@ -2395,8 +2401,7 @@
minTopPosition = firstVisibleSection.getBounds().top;
}
boolean shiftPulsingWithFirst = mNumHeadsUp <= 1
- && (mAmbientState.isDozing()
- || (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard));
+ && (mAmbientState.isDozing() || (mKeyguardBypassEnabled && onKeyguard));
for (NotificationSection section : mSections) {
int minBottomPosition = minTopPosition;
if (section == lastSection) {
@@ -2539,7 +2544,7 @@
} else {
mTopPaddingOverflow = 0;
}
- setTopPadding(topPadding, animate && !mKeyguardBypassEnabledProvider.getBypassEnabled());
+ setTopPadding(topPadding, animate && !mKeyguardBypassEnabled);
setExpandedHeight(mExpandedHeight);
}
@@ -3103,7 +3108,7 @@
boolean performDisappearAnimation = !mIsExpanded
// Only animate if we still have pinned heads up, otherwise we just have the
// regular collapse animation of the lock screen
- || (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()
+ || (mKeyguardBypassEnabled && onKeyguard()
&& mInHeadsUpPinnedMode);
if (performDisappearAnimation && !isHeadsUp) {
type = row.wasJustClicked()
@@ -4326,7 +4331,7 @@
// Since we are clipping to the outline we need to make sure that the shadows aren't
// clipped when pulsing
float ownTranslationZ = 0;
- if (mKeyguardBypassEnabledProvider.getBypassEnabled() && mAmbientState.isHiddenAtAll()) {
+ if (mKeyguardBypassEnabled && mAmbientState.isHiddenAtAll()) {
ExpandableView firstChildNotGone = getFirstChildNotGone();
if (firstChildNotGone != null && firstChildNotGone.showingPulsing()) {
ownTranslationZ = firstChildNotGone.getTranslationZ();
@@ -4368,6 +4373,14 @@
return -1;
}
+ /**
+ * Returns whether or not a History button is shown in the footer. If there is no footer, then
+ * this will return false.
+ **/
+ public boolean isHistoryShown() {
+ return mFooterView != null && mFooterView.isHistoryShown();
+ }
+
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
void setFooterView(@NonNull FooterView footerView) {
int index = -1;
@@ -4377,6 +4390,9 @@
}
mFooterView = footerView;
addView(mFooterView, index);
+ if (mManageButtonClickListener != null) {
+ mFooterView.setManageButtonClickListener(mManageButtonClickListener);
+ }
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5090,9 +5106,12 @@
}
}
- public void setNotificationActivityStarter(
- NotificationActivityStarter notificationActivityStarter) {
- mNotificationActivityStarter = notificationActivityStarter;
+ /** Register a {@link View.OnClickListener} to be invoked when the Manage button is clicked. */
+ public void setManageButtonClickListener(@Nullable OnClickListener listener) {
+ mManageButtonClickListener = listener;
+ if (mFooterView != null) {
+ mFooterView.setManageButtonClickListener(mManageButtonClickListener);
+ }
}
@VisibleForTesting
@@ -5106,9 +5125,6 @@
}
clearNotifications(ROWS_ALL, true /* closeShade */);
});
- footerView.setManageButtonClickListener(v -> {
- mNotificationActivityStarter.startHistoryIntent(v, mFooterView.isHistoryShown());
- });
setFooterView(footerView);
}
@@ -5159,7 +5175,7 @@
*/
public float setPulseHeight(float height) {
mAmbientState.setPulseHeight(height);
- if (mKeyguardBypassEnabledProvider.getBypassEnabled()) {
+ if (mKeyguardBypassEnabled) {
notifyAppearChangedListeners();
}
requestChildrenUpdate();
@@ -6090,10 +6106,6 @@
/** Only rows where entry.isHighPriority() is false. */
public static final int ROWS_GENTLE = 2;
- interface KeyguardBypassEnabledProvider {
- boolean getBypassEnabled();
- }
-
interface DismissListener {
void onDismiss(@SelectedRows int selectedRows);
}
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 a47afb2..8ee0cd1 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
@@ -48,6 +48,8 @@
import android.view.ViewGroup;
import android.view.WindowInsets;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.jank.InteractionJankMonitor;
@@ -184,6 +186,9 @@
private final NotificationListContainerImpl mNotificationListContainer =
new NotificationListContainerImpl();
+ @Nullable
+ private NotificationActivityStarter mNotificationActivityStarter;
+
private ColorExtractor.OnColorsChangedListener mOnColorsChangedListener;
/**
@@ -708,8 +713,15 @@
});
}
- mView.initView(mView.getContext(), mKeyguardBypassController::getBypassEnabled,
- mSwipeHelper);
+ mView.initView(mView.getContext(), mSwipeHelper);
+ mView.setKeyguardBypassEnabled(mKeyguardBypassController.getBypassEnabled());
+ mKeyguardBypassController
+ .registerOnBypassStateChangedListener(mView::setKeyguardBypassEnabled);
+ mView.setManageButtonClickListener(v -> {
+ if (mNotificationActivityStarter != null) {
+ mNotificationActivityStarter.startHistoryIntent(v, mView.isHistoryShown());
+ }
+ });
mHeadsUpManager.addListener(mOnHeadsUpChangedListener);
mHeadsUpManager.setAnimationStateHandler(mView::setHeadsUpGoingAwayAnimationsAllowed);
@@ -1480,6 +1492,10 @@
mView.animateNextTopPaddingChange();
}
+ public void setNotificationActivityStarter(NotificationActivityStarter activityStarter) {
+ mNotificationActivityStarter = activityStarter;
+ }
+
/**
* Enum for UiEvent logged from this class
*/
@@ -1551,7 +1567,8 @@
@Override
public void setNotificationActivityStarter(
NotificationActivityStarter notificationActivityStarter) {
- mView.setNotificationActivityStarter(notificationActivityStarter);
+ NotificationStackScrollLayoutController.this
+ .setNotificationActivityStarter(notificationActivityStarter);
}
@Override
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 e65038b..f460a13 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
@@ -148,8 +148,22 @@
AmbientState ambientState) {
NotificationShelf shelf = ambientState.getShelf();
- if (shelf != null) {
- shelf.updateState(algorithmState, ambientState);
+ if (shelf == null) {
+ return;
+ }
+
+ shelf.updateState(algorithmState, ambientState);
+
+ // After the shelf has updated its yTranslation,
+ // explicitly hide views below the shelf to skip rendering them in the hardware layer.
+ final float shelfTop = shelf.getViewState().yTranslation;
+
+ for (ExpandableView view : algorithmState.visibleChildren) {
+ final float viewTop = view.getViewState().yTranslation;
+
+ if (viewTop >= shelfTop) {
+ view.getViewState().hidden = true;
+ }
}
}
@@ -411,8 +425,7 @@
} else {
if (view != ambientState.getTrackedHeadsUpRow()) {
if (ambientState.isExpansionChanging()) {
- // Show all views. Views below the shelf will later be clipped (essentially
- // hidden) in NotificationShelf.
+ // We later update shelf state, then hide views below the shelf.
viewState.hidden = false;
viewState.inShelf = algorithmState.firstViewInShelf != null
&& i >= algorithmState.visibleChildren.indexOf(
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 16f8319..91d503b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -74,6 +74,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.settingslib.Utils;
import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -459,6 +460,10 @@
if (tileIcon != null) {
mWalletButton.setImageDrawable(tileIcon);
}
+ mWalletButton.getDrawable().setTint(
+ Utils.getColorAttr(
+ mContext,
+ com.android.internal.R.attr.textColorPrimary).getDefaultColor());
mWalletButton.setVisibility(VISIBLE);
mWalletButton.setOnClickListener(this::onWalletClick);
mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index d6ea4a8..8c0dfc5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -87,7 +87,7 @@
private final Runnable mResetRunnable = ()-> {
if (mKeyguardViewController != null) {
mKeyguardViewController.resetSecurityContainer();
- for (KeyguardResetCallback callback : mResetCallbacks) {
+ for (KeyguardResetCallback callback : new ArrayList<>(mResetCallbacks)) {
callback.onKeyguardReset();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 2cb0a3a..99df3f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -43,6 +43,11 @@
@BypassOverride private val bypassOverride: Int
private var hasFaceFeature: Boolean
private var pendingUnlock: PendingUnlock? = null
+ private val listeners = mutableListOf<OnBypassStateChangedListener>()
+
+ private val faceAuthEnabledChangedCallback = object : KeyguardStateController.Callback {
+ override fun onFaceAuthEnabledChanged() = notifyListeners()
+ }
@IntDef(
FACE_UNLOCK_BYPASS_NO_OVERRIDE,
@@ -83,7 +88,10 @@
}
return enabled && mKeyguardStateController.isFaceAuthEnabled
}
- private set
+ private set(value) {
+ field = value
+ notifyListeners()
+ }
var bouncerShowing: Boolean = false
var altBouncerShowing: Boolean = false
@@ -140,6 +148,8 @@
})
}
+ private fun notifyListeners() = listeners.forEach { it.onBypassStateChanged(bypassEnabled) }
+
/**
* Notify that the biometric unlock has happened.
*
@@ -223,6 +233,32 @@
pw.println(" hasFaceFeature: $hasFaceFeature")
}
+ /** Registers a listener for bypass state changes. */
+ fun registerOnBypassStateChangedListener(listener: OnBypassStateChangedListener) {
+ val start = listeners.isEmpty()
+ listeners.add(listener)
+ if (start) {
+ mKeyguardStateController.addCallback(faceAuthEnabledChangedCallback)
+ }
+ }
+
+ /**
+ * Unregisters a listener for bypass state changes, previous registered with
+ * [registerOnBypassStateChangedListener]
+ */
+ fun unregisterOnBypassStateChangedListener(listener: OnBypassStateChangedListener) {
+ listeners.remove(listener)
+ if (listeners.isEmpty()) {
+ mKeyguardStateController.removeCallback(faceAuthEnabledChangedCallback)
+ }
+ }
+
+ /** Listener for bypass state change events. */
+ interface OnBypassStateChangedListener {
+ /** Invoked when bypass becomes enabled or disabled. */
+ fun onBypassStateChanged(isEnabled: Boolean)
+ }
+
companion object {
const val BYPASS_FADE_DURATION = 67
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
index 7d13405..c213707 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
@@ -21,6 +21,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.Nullable;
+import android.view.InsetsState;
import android.view.View;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -149,7 +150,7 @@
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, boolean isFullscreen) {
+ @Behavior int behavior, InsetsState requestedState, String packageName) {
if (displayId != mDisplayId) {
return;
}
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 8d08449..22952aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -21,6 +21,7 @@
import static androidx.constraintlayout.widget.ConstraintSet.END;
import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
import static androidx.constraintlayout.widget.ConstraintSet.START;
+import static androidx.constraintlayout.widget.ConstraintSet.TOP;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
@@ -28,6 +29,8 @@
import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.StatusBarState.SHADE;
+import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
import static java.lang.Float.isNaN;
@@ -117,6 +120,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.qs.QSDetailDisplayer;
+import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
@@ -331,6 +335,8 @@
private final int mMaxKeyguardNotifications;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final TapAgainViewController mTapAgainViewController;
+ private final SplitShadeHeaderController mSplitShadeHeaderController;
+ private final RecordingController mRecordingController;
private boolean mShouldUseSplitNotificationShade;
// The bottom padding reserved for elements of the keyguard measuring notifications
private float mKeyguardNotificationBottomPadding;
@@ -395,7 +401,7 @@
private float mDownY;
private int mDisplayTopInset = 0; // in pixels
private int mDisplayRightInset = 0; // in pixels
- private int mSplitShadeNotificationsTopPadding;
+ private int mSplitShadeStatusBarHeight;
private final KeyguardClockPositionAlgorithm
mClockPositionAlgorithm =
@@ -719,8 +725,10 @@
FragmentService fragmentService,
ContentResolver contentResolver,
QuickAccessWalletController quickAccessWalletController,
+ RecordingController recordingController,
@Main Executor uiExecutor,
SecureSettings secureSettings,
+ SplitShadeHeaderController splitShadeHeaderController,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
NotificationRemoteInputManager remoteInputManager) {
super(view, falsingManager, dozeLog, keyguardStateController,
@@ -754,6 +762,7 @@
mShouldUseSplitNotificationShade =
Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources);
mView.setWillNotDraw(!DEBUG);
+ mSplitShadeHeaderController = splitShadeHeaderController;
mLayoutInflater = layoutInflater;
mFalsingManager = falsingManager;
mFalsingCollector = falsingCollector;
@@ -763,6 +772,7 @@
mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
setPanelAlpha(255, false /* animate */);
mCommandQueue = commandQueue;
+ mRecordingController = recordingController;
mDisplayId = displayId;
mPulseExpansionHandler = pulseExpansionHandler;
mDozeParameters = dozeParameters;
@@ -1022,8 +1032,8 @@
public void updateResources() {
mQuickQsOffsetHeight = mResources.getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_offset_height);
- mSplitShadeNotificationsTopPadding =
- mResources.getDimensionPixelSize(R.dimen.notifications_top_padding_split_shade);
+ mSplitShadeStatusBarHeight =
+ mResources.getDimensionPixelSize(R.dimen.split_shade_header_height);
int qsWidth = mResources.getDimensionPixelSize(R.dimen.qs_panel_width);
int panelWidth = mResources.getDimensionPixelSize(R.dimen.notification_panel_width);
mShouldUseSplitNotificationShade =
@@ -1032,6 +1042,11 @@
if (mQs != null) {
mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade);
}
+
+ int topMargin = mShouldUseSplitNotificationShade ? mSplitShadeStatusBarHeight :
+ mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_top);
+ mSplitShadeHeaderController.setSplitShadeMode(mShouldUseSplitNotificationShade);
+
// To change the constraints at runtime, all children of the ConstraintLayout must have ids
ensureAllViewsHaveIds(mNotificationContainerParent);
ConstraintSet constraintSet = new ConstraintSet();
@@ -1050,6 +1065,8 @@
}
constraintSet.getConstraint(R.id.notification_stack_scroller).layout.mWidth = panelWidth;
constraintSet.getConstraint(R.id.qs_frame).layout.mWidth = qsWidth;
+ constraintSet.setMargin(R.id.notification_stack_scroller, TOP, topMargin);
+ constraintSet.setMargin(R.id.qs_frame, TOP, topMargin);
constraintSet.applyTo(mNotificationContainerParent);
updateKeyguardStatusViewAlignment(false /* animate */);
@@ -1615,7 +1632,10 @@
public void expandWithQsDetail(DetailAdapter qsDetailAdapter) {
traceQsJank(true /* startTracing */, false /* wasCancelled */);
flingSettings(0 /* velocity */, FLING_EXPAND);
- mQSDetailDisplayer.showDetailAdapter(qsDetailAdapter, 0, 0);
+ // When expanding with a panel, there's no meaningful touch point to correspond to. Set the
+ // origin to somewhere above the screen. This is used for animations.
+ int x = mQsFrame.getWidth() / 2;
+ mQSDetailDisplayer.showDetailAdapter(qsDetailAdapter, x, -getHeight());
if (mAccessibilityManager.isEnabled()) {
mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
}
@@ -2339,8 +2359,8 @@
left = 0;
right = getView().getRight() + mDisplayRightInset;
} else {
- top = Math.min(qsPanelBottomY, mSplitShadeNotificationsTopPadding);
- bottom = mNotificationStackScrollLayoutController.getHeight();
+ top = Math.min(qsPanelBottomY, mSplitShadeStatusBarHeight);
+ bottom = top + mNotificationStackScrollLayoutController.getHeight();
left = mNotificationStackScrollLayoutController.getLeft();
right = mNotificationStackScrollLayoutController.getRight();
}
@@ -2404,7 +2424,8 @@
// The padding on this area is large enough that we can use a cheaper clipping strategy
mKeyguardStatusAreaClipBounds.set(left, top, right, bottom);
clipStatusView = qsVisible;
- radius = (int) MathUtils.lerp(mScreenCornerRadius, mScrimCornerRadius,
+ float screenCornerRadius = mRecordingController.isRecording() ? 0 : mScreenCornerRadius;
+ radius = (int) MathUtils.lerp(screenCornerRadius, mScrimCornerRadius,
Math.min(top / (float) mScrimCornerRadius, 1f));
statusBarClipTop = top - mKeyguardStatusBar.getTop();
}
@@ -2438,7 +2459,7 @@
int nsslLeft = left - mNotificationStackScrollLayoutController.getLeft();
int nsslRight = right - mNotificationStackScrollLayoutController.getLeft();
int nsslTop = top - mNotificationStackScrollLayoutController.getTop();
- int nsslBottom = bottom - mNotificationStackScrollLayoutController.getTop();
+ int nsslBottom = bottom;
int bottomRadius = mShouldUseSplitNotificationShade ? radius : 0;
mNotificationStackScrollLayoutController.setRoundedClippingBounds(
nsslLeft, nsslTop, nsslRight, nsslBottom, radius, bottomRadius);
@@ -2479,7 +2500,7 @@
private float calculateNotificationsTopPadding() {
if (mShouldUseSplitNotificationShade && !mKeyguardShowing) {
- return mSplitShadeNotificationsTopPadding + mQsNotificationTopPadding;
+ return 0;
}
if (mKeyguardShowing && (mQsExpandImmediate
|| mIsExpanding && mQsExpandedWhenExpandingStarted)) {
@@ -4461,6 +4482,8 @@
maybeAnimateBottomAreaAlpha();
resetHorizontalPanelPosition();
updateQsState();
+ mSplitShadeHeaderController.setShadeExpanded(
+ mBarState == SHADE || mBarState == SHADE_LOCKED);
}
@Override
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 0ff6490..1a404dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -55,16 +55,18 @@
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.google.android.collect.Lists;
-
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -100,7 +102,7 @@
private ForcePluginOpenListener mForcePluginOpenListener;
private Consumer<Integer> mScrimsVisibilityListener;
private final ArrayList<WeakReference<StatusBarWindowCallback>>
- mCallbacks = Lists.newArrayList();
+ mCallbacks = new ArrayList<>();
private final SysuiColorExtractor mColorExtractor;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@@ -464,14 +466,16 @@
@Override
public void notifyStateChangedCallbacks() {
- for (int i = 0; i < mCallbacks.size(); i++) {
- StatusBarWindowCallback cb = mCallbacks.get(i).get();
- if (cb != null) {
- cb.onStateChanged(mCurrentState.mKeyguardShowing,
- mCurrentState.mKeyguardOccluded,
- mCurrentState.mBouncerShowing,
- mCurrentState.mDozing);
- }
+ // Copy callbacks to separate ArrayList to avoid concurrent modification
+ List<StatusBarWindowCallback> activeCallbacks = mCallbacks.stream()
+ .map(Reference::get)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ for (StatusBarWindowCallback cb : activeCallbacks) {
+ cb.onStateChanged(mCurrentState.mKeyguardShowing,
+ mCurrentState.mKeyguardOccluded,
+ mCurrentState.mBouncerShowing,
+ mCurrentState.mDozing);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index ed7ab6cf..7b110a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -107,7 +107,8 @@
private final String mSlotBluetooth;
private final String mSlotTty;
private final String mSlotZen;
- private final String mSlotVolume;
+ private final String mSlotMute;
+ private final String mSlotVibrate;
private final String mSlotAlarmClock;
private final String mSlotManagedProfile;
private final String mSlotRotate;
@@ -149,7 +150,8 @@
private final PrivacyLogger mPrivacyLogger;
private boolean mZenVisible;
- private boolean mVolumeVisible;
+ private boolean mVibrateVisible;
+ private boolean mMuteVisible;
private boolean mCurrentUserSetup;
private boolean mManagedProfileIconVisible = false;
@@ -207,7 +209,8 @@
mSlotBluetooth = resources.getString(com.android.internal.R.string.status_bar_bluetooth);
mSlotTty = resources.getString(com.android.internal.R.string.status_bar_tty);
mSlotZen = resources.getString(com.android.internal.R.string.status_bar_zen);
- mSlotVolume = resources.getString(com.android.internal.R.string.status_bar_volume);
+ mSlotMute = resources.getString(com.android.internal.R.string.status_bar_mute);
+ mSlotVibrate = resources.getString(com.android.internal.R.string.status_bar_volume);
mSlotAlarmClock = resources.getString(com.android.internal.R.string.status_bar_alarm_clock);
mSlotManagedProfile = resources.getString(
com.android.internal.R.string.status_bar_managed_profile);
@@ -264,9 +267,14 @@
mIconController.setIcon(mSlotZen, R.drawable.stat_sys_dnd, null);
mIconController.setIconVisibility(mSlotZen, false);
- // volume
- mIconController.setIcon(mSlotVolume, R.drawable.stat_sys_ringer_vibrate, null);
- mIconController.setIconVisibility(mSlotVolume, false);
+ // vibrate
+ mIconController.setIcon(mSlotVibrate, R.drawable.stat_sys_ringer_vibrate,
+ mResources.getString(R.string.accessibility_ringer_vibrate));
+ mIconController.setIconVisibility(mSlotVibrate, false);
+ // mute
+ mIconController.setIcon(mSlotMute, R.drawable.stat_sys_ringer_silent,
+ mResources.getString(R.string.accessibility_ringer_silent));
+ mIconController.setIconVisibility(mSlotMute, false);
updateVolumeZen();
// cast
@@ -372,9 +380,8 @@
int zenIconId = 0;
String zenDescription = null;
- boolean volumeVisible = false;
- int volumeIconId = 0;
- String volumeDescription = null;
+ boolean vibrateVisible = false;
+ boolean muteVisible = false;
int zen = mZenController.getZen();
if (DndTile.isVisible(mSharedPreferences) || DndTile.isCombinedIcon(mSharedPreferences)) {
@@ -396,13 +403,9 @@
mRingerModeTracker.getRingerModeInternal().getValue();
if (ringerModeInternal != null) {
if (ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) {
- volumeVisible = true;
- volumeIconId = R.drawable.stat_sys_ringer_vibrate;
- volumeDescription = mResources.getString(R.string.accessibility_ringer_vibrate);
+ vibrateVisible = true;
} else if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) {
- volumeVisible = true;
- volumeIconId = R.drawable.stat_sys_ringer_silent;
- volumeDescription = mResources.getString(R.string.accessibility_ringer_silent);
+ muteVisible = true;
}
}
}
@@ -415,13 +418,16 @@
mZenVisible = zenVisible;
}
- if (volumeVisible) {
- mIconController.setIcon(mSlotVolume, volumeIconId, volumeDescription);
+ if (vibrateVisible != mVibrateVisible) {
+ mIconController.setIconVisibility(mSlotVibrate, vibrateVisible);
+ mVibrateVisible = vibrateVisible;
}
- if (volumeVisible != mVolumeVisible) {
- mIconController.setIconVisibility(mSlotVolume, volumeVisible);
- mVolumeVisible = volumeVisible;
+
+ if (muteVisible != mMuteVisible) {
+ mIconController.setIconVisibility(mSlotMute, muteVisible);
+ mMuteVisible = muteVisible;
}
+
updateAlarm();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
new file mode 100644
index 0000000..d29107d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
@@ -0,0 +1,83 @@
+/*
+ * 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 android.view.View
+import com.android.systemui.BatteryMeterView
+import com.android.systemui.R
+import com.android.systemui.qs.carrier.QSCarrierGroupController
+import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope
+import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SPLIT_SHADE_HEADER
+import javax.inject.Inject
+import javax.inject.Named
+
+@StatusBarScope
+class SplitShadeHeaderController @Inject constructor(
+ @Named(SPLIT_SHADE_HEADER) private val statusBar: View,
+ private val statusBarIconController: StatusBarIconController,
+ qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder,
+ featureFlags: FeatureFlags
+) {
+
+ private val iconManager: StatusBarIconController.IconManager
+ private val qsCarrierGroupController: QSCarrierGroupController
+ private var visible = false
+
+ var shadeExpanded = false
+ set(value) {
+ field = value
+ updateVisibility()
+ }
+
+ var splitShadeMode = false
+ set(value) {
+ field = value
+ updateVisibility()
+ }
+
+ init {
+ val batteryIcon: BatteryMeterView = statusBar.findViewById(R.id.batteryRemainingIcon)
+ // battery settings same as in QS icons
+ batteryIcon.setIgnoreTunerUpdates(true)
+ batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
+
+ val iconContainer: StatusIconContainer = statusBar.findViewById(R.id.statusIcons)
+ iconManager = StatusBarIconController.IconManager(iconContainer, featureFlags)
+ qsCarrierGroupController = qsCarrierGroupControllerBuilder
+ .setQSCarrierGroup(statusBar.findViewById(R.id.carrier_group))
+ .build()
+ }
+
+ private fun updateVisibility() {
+ val shouldBeVisible = shadeExpanded && splitShadeMode
+ if (visible != shouldBeVisible) {
+ visible = shouldBeVisible
+ statusBar.visibility = if (shouldBeVisible) View.VISIBLE else View.GONE
+ updateListeners(shouldBeVisible)
+ }
+ }
+
+ private fun updateListeners(visible: Boolean) {
+ qsCarrierGroupController.setListening(visible)
+ if (visible) {
+ statusBarIconController.addIconGroup(iconManager)
+ } else {
+ statusBarIconController.removeIconGroup(iconManager)
+ }
+ }
+}
\ 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 89711fa..e3b2a2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -104,6 +104,7 @@
import android.view.Display;
import android.view.IRemoteAnimationRunner;
import android.view.IWindowManager;
+import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -247,6 +248,7 @@
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+import com.android.wm.shell.startingsurface.StartingSurface;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -685,9 +687,7 @@
new FalsingManager.FalsingBeliefListener() {
@Override
public void onFalse() {
- // Hides quick settings.
- mNotificationPanelViewController.resetViews(true);
- // Hides bouncer and quick-quick settings.
+ // Hides quick settings, bouncer, and quick-quick settings.
mStatusBarKeyguardViewManager.reset(true);
}
};
@@ -705,6 +705,7 @@
private final Optional<BubblesManager> mBubblesManagerOptional;
private final Optional<Bubbles> mBubblesOptional;
private final Bubbles.BubbleExpandListener mBubbleExpandListener;
+ private final Optional<StartingSurface> mStartingSurfaceOptional;
private ActivityIntentHelper mActivityIntentHelper;
private NotificationStackScrollLayoutController mStackScrollerController;
@@ -804,7 +805,8 @@
LockscreenShadeTransitionController lockscreenShadeTransitionController,
FeatureFlags featureFlags,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
- UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) {
+ UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
+ Optional<StartingSurface> startingSurfaceOptional) {
super(context);
mNotificationsController = notificationsController;
mLightBarController = lightBarController;
@@ -891,6 +893,7 @@
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
+ mStartingSurfaceOptional = startingSurfaceOptional;
lockscreenShadeTransitionController.setStatusbar(this);
mExpansionChangedListeners = new ArrayList<>();
@@ -984,7 +987,8 @@
showTransientUnchecked();
}
onSystemBarAttributesChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions,
- result.mNavbarColorManagedByIme, result.mBehavior, result.mAppFullscreen);
+ result.mNavbarColorManagedByIme, result.mBehavior, result.mRequestedState,
+ result.mPackageName);
// StatusBarManagerService has a back up of IME token and it's restored here.
setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis,
@@ -1419,7 +1423,9 @@
private void setUpPresenter() {
// Set up the initial notification state.
- mActivityLaunchAnimator = new ActivityLaunchAnimator(this, mContext);
+ mActivityLaunchAnimator = new ActivityLaunchAnimator(this,
+ mStartingSurfaceOptional.orElse(null),
+ mContext);
mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider(
mNotificationShadeWindowViewController,
mStackScrollerController.getNotificationListContainer(),
@@ -1447,7 +1453,7 @@
.setNotificationPresenter(mPresenter)
.setNotificationPanelViewController(mNotificationPanelViewController)
.build();
- mStackScroller.setNotificationActivityStarter(mNotificationActivityStarter);
+ mStackScrollerController.setNotificationActivityStarter(mNotificationActivityStarter);
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
mNotificationsController.initialize(
@@ -2477,7 +2483,7 @@
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, boolean isFullscreen) {
+ @Behavior int behavior, InsetsState requestedState, String packageName) {
if (displayId != mDisplayId) {
return;
}
@@ -2490,7 +2496,8 @@
mStatusBarMode, navbarColorManagedByIme);
updateBubblesVisibility();
- mStatusBarStateController.setFullscreenState(isFullscreen);
+ mStatusBarStateController.setSystemBarAttributes(
+ appearance, behavior, requestedState, packageName);
}
@Override
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 e009c0c..95fd886d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -521,7 +521,9 @@
@Override
public void reset(boolean hideBouncerWhenShowing) {
if (mShowing) {
- mNotificationPanelViewController.closeQs();
+ // Hide quick settings.
+ mNotificationPanelViewController.resetViews(/* animate= */ true);
+ // Hide bouncer and quick-quick settings.
if (mOccluded && !mDozing) {
mStatusBar.hideKeyguard();
if (hideBouncerWhenShowing || mBouncer.needsFullscreenBouncer()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 98b9cc9..9a6dd38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -514,7 +514,8 @@
InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON
);
ActivityLaunchAnimator.Controller animationController =
- new StatusBarLaunchAnimatorController(viewController, mStatusBar,
+ viewController == null ? null
+ : new StatusBarLaunchAnimatorController(viewController, mStatusBar,
true /* isActivityIntent */);
mActivityLaunchAnimator.startIntentWithAnimation(animationController, animate,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
index fb25ae3..4e632c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
@@ -23,6 +23,7 @@
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController;
+import com.android.systemui.statusbar.phone.SplitShadeHeaderController;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
import java.lang.annotation.Documented;
@@ -86,4 +87,10 @@
*/
@StatusBarScope
AuthRippleController getAuthRippleController();
+
+ /**
+ * Creates a SplitShadeStatusBarController.
+ */
+ @StatusBarScope
+ SplitShadeHeaderController getSplitShadeStatusBarController();
}
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 2611ab5..716d1db 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
@@ -109,6 +109,7 @@
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+import com.android.wm.shell.startingsurface.StartingSurface;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -218,7 +219,8 @@
LockscreenShadeTransitionController transitionController,
FeatureFlags featureFlags,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
- UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) {
+ UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
+ Optional<StartingSurface> startingSurfaceOptional) {
return new StatusBar(
context,
notificationsController,
@@ -306,6 +308,7 @@
transitionController,
featureFlags,
keyguardUnlockAnimationController,
- unlockedScreenOffAnimationController);
+ unlockedScreenOffAnimationController,
+ startingSurfaceOptional);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 27d71ed..d691dca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone.dagger;
import android.annotation.Nullable;
+import android.view.View;
import com.android.keyguard.LockIconView;
import com.android.systemui.R;
@@ -25,11 +26,16 @@
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
import com.android.systemui.statusbar.phone.TapAgainView;
+import javax.inject.Named;
+
import dagger.Module;
import dagger.Provides;
@Module
public abstract class StatusBarViewModule {
+
+ public static final String SPLIT_SHADE_HEADER = "split_shade_header";
+
/** */
@Provides
@StatusBarComponent.StatusBarScope
@@ -57,6 +63,15 @@
/** */
@Provides
+ @Named(SPLIT_SHADE_HEADER)
+ @StatusBarComponent.StatusBarScope
+ public static View getSlitShadeStatusBarView(
+ NotificationShadeWindowView notificationShadeWindowView) {
+ return notificationShadeWindowView.findViewById(R.id.split_shade_status_bar);
+ }
+
+ /** */
+ @Provides
@StatusBarComponent.StatusBarScope
public static TapAgainView getTapAgainView(NotificationPanelView npv) {
return npv.getTapAgainView();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 081fe5a..a8097c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -41,6 +41,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashSet;
/**
@@ -157,7 +158,7 @@
NotificationPeekEvent.NOTIFICATION_PEEK, entry.getSbn().getUid(),
entry.getSbn().getPackageName(), entry.getSbn().getInstanceId());
}
- for (OnHeadsUpChangedListener listener : mListeners) {
+ for (OnHeadsUpChangedListener listener : new ArrayList<>(mListeners)) {
if (isPinned) {
listener.onHeadsUpPinned(entry);
} else {
@@ -177,7 +178,7 @@
entry.setHeadsUp(true);
setEntryPinned((HeadsUpEntry) alertEntry, shouldHeadsUpBecomePinned(entry));
EventLogTags.writeSysuiHeadsUpStatus(entry.getKey(), 1 /* visible */);
- for (OnHeadsUpChangedListener listener : mListeners) {
+ for (OnHeadsUpChangedListener listener : new ArrayList<>(mListeners)) {
listener.onHeadsUpStateChanged(entry, true);
}
}
@@ -188,7 +189,7 @@
entry.setHeadsUp(false);
setEntryPinned((HeadsUpEntry) alertEntry, false /* isPinned */);
EventLogTags.writeSysuiHeadsUpStatus(entry.getKey(), 0 /* visible */);
- for (OnHeadsUpChangedListener listener : mListeners) {
+ for (OnHeadsUpChangedListener listener : new ArrayList<>(mListeners)) {
listener.onHeadsUpStateChanged(entry, false);
}
}
@@ -206,7 +207,7 @@
if (mHasPinnedNotification) {
MetricsLogger.count(mContext, "note_peek", 1);
}
- for (OnHeadsUpChangedListener listener : mListeners) {
+ for (OnHeadsUpChangedListener listener : new ArrayList<>(mListeners)) {
listener.onHeadsUpPinnedModeChanged(hasPinnedNotification);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
index acfdda4..e01b95e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
@@ -29,7 +29,7 @@
void setSensorBlocked(@Source int source, @Sensor int sensor, boolean blocked);
- void suppressSensorPrivacyReminders(String packageName, boolean suppress);
+ void suppressSensorPrivacyReminders(int sensor, boolean suppress);
interface Callback {
void onSensorBlockedChanged(@Sensor int sensor, boolean blocked);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
index 9807165..1d71301 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
@@ -68,8 +68,8 @@
}
@Override
- public void suppressSensorPrivacyReminders(String packageName, boolean suppress) {
- mSensorPrivacyManager.suppressSensorPrivacyReminders(packageName, suppress);
+ public void suppressSensorPrivacyReminders(int sensor, boolean suppress) {
+ mSensorPrivacyManager.suppressSensorPrivacyReminders(sensor, suppress);
}
@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 fcfc967..742b1ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -245,5 +245,11 @@
* animation.
*/
default void onKeyguardDismissAmountChanged() {}
+
+ /**
+ * Triggered when face auth becomes available or unavailable. Value should be queried with
+ * {@link KeyguardStateController#isFaceAuthEnabled()}.
+ */
+ default void onFaceAuthEnabledChanged() {}
}
}
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 ff3fed6..3327817 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -805,7 +805,7 @@
}
private void onEditTextFocusChanged(RemoteEditText remoteEditText, boolean focused) {
- for (View.OnFocusChangeListener listener : mEditTextFocusChangeListeners) {
+ for (View.OnFocusChangeListener listener : new ArrayList<>(mEditTextFocusChangeListeners)) {
listener.onFocusChange(remoteEditText, focused);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 4738ddb..9355244 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -455,19 +455,23 @@
OverlayIdentifier systemPalette = categoryToPackage.get(OVERLAY_CATEGORY_SYSTEM_PALETTE);
if (mIsMonetEnabled && systemPalette != null && systemPalette.getPackageName() != null) {
try {
- int color = Integer.parseInt(systemPalette.getPackageName().toLowerCase(), 16);
+ String colorString = systemPalette.getPackageName().toLowerCase();
+ if (!colorString.startsWith("#")) {
+ colorString = "#" + colorString;
+ }
+ int color = Color.parseColor(colorString);
mNeutralOverlay = getOverlay(color, NEUTRAL);
mNeedsOverlayCreation = true;
categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE);
- } catch (NumberFormatException e) {
- Log.w(TAG, "Invalid color definition: " + systemPalette.getPackageName());
+ } catch (Exception e) {
+ // Color.parseColor doesn't catch any exceptions from the calls it makes
+ Log.w(TAG, "Invalid color definition: " + systemPalette.getPackageName(), e);
}
} else if (!mIsMonetEnabled && systemPalette != null) {
try {
// It's possible that we flipped the flag off and still have a @ColorInt in the
// setting. We need to sanitize the input, otherwise the overlay transaction will
// fail.
- Integer.parseInt(systemPalette.getPackageName().toLowerCase(), 16);
categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE);
} catch (NumberFormatException e) {
// This is a package name. All good, let's continue
@@ -478,12 +482,17 @@
OverlayIdentifier accentPalette = categoryToPackage.get(OVERLAY_CATEGORY_ACCENT_COLOR);
if (mIsMonetEnabled && accentPalette != null && accentPalette.getPackageName() != null) {
try {
- int color = Integer.parseInt(accentPalette.getPackageName().toLowerCase(), 16);
+ String colorString = accentPalette.getPackageName().toLowerCase();
+ if (!colorString.startsWith("#")) {
+ colorString = "#" + colorString;
+ }
+ int color = Color.parseColor(colorString);
mSecondaryOverlay = getOverlay(color, ACCENT);
mNeedsOverlayCreation = true;
categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR);
- } catch (NumberFormatException e) {
- Log.w(TAG, "Invalid color definition: " + accentPalette.getPackageName());
+ } catch (Exception e) {
+ // Color.parseColor doesn't catch any exceptions from the calls it makes
+ Log.w(TAG, "Invalid color definition: " + accentPalette.getPackageName(), e);
}
} else if (!mIsMonetEnabled && accentPalette != null) {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java b/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java
index 361604c..a40cf4f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java
@@ -101,7 +101,12 @@
@Override
public void onDismiss(DialogInterface unused) {
- mContext.unregisterReceiver(mReceiver);
+ try {
+ mContext.unregisterReceiver(mReceiver);
+ } catch (IllegalArgumentException e) {
+ // Don't crash if the receiver has already been unregistered.
+ e.printStackTrace();
+ }
cleanUp();
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 9446732..f317628 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -1750,7 +1750,7 @@
mContext, android.R.attr.colorBackgroundFloating);
final ColorStateList inverseTextTint = Utils.getColorAttr(
- mContext, com.android.internal.R.attr.textColorPrimaryInverse);
+ mContext, com.android.internal.R.attr.textColorOnAccent);
row.sliderProgressSolid.setTintList(colorTint);
if (row.sliderBgIcon != null) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index 0f3892a..fe5633e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -505,6 +505,30 @@
expectedY, mWindowManager.getLayoutParamsFromAttachedView().y);
}
+ @Test
+ public void onScreenSizeChanged_buttonIsShowingOnTheRightSide_expectedPosition() {
+ final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+ final Rect oldDraggableBounds = new Rect(mMagnificationModeSwitch.mDraggableWindowBounds);
+ final float windowHeightFraction =
+ (float) (mWindowManager.getLayoutParamsFromAttachedView().y
+ - oldDraggableBounds.top) / oldDraggableBounds.height();
+
+ // The window bounds and the draggable bounds are changed due to the screen size change.
+ final Rect tmpRect = new Rect(windowBounds);
+ tmpRect.scale(2);
+ final Rect newWindowBounds = new Rect(tmpRect);
+ mWindowManager.setWindowBounds(newWindowBounds);
+ mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_SCREEN_SIZE);
+
+ final int expectedX = mMagnificationModeSwitch.mDraggableWindowBounds.right;
+ final int expectedY = (int) (windowHeightFraction
+ * mMagnificationModeSwitch.mDraggableWindowBounds.height())
+ + mMagnificationModeSwitch.mDraggableWindowBounds.top;
+ assertEquals(expectedX, mWindowManager.getLayoutParamsFromAttachedView().x);
+ assertEquals(expectedY, mWindowManager.getLayoutParamsFromAttachedView().y);
+ }
+
private void assertModeUnchanged(int expectedMode) {
final int actualMode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
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 d01cdd4..694b84a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
@@ -10,21 +10,25 @@
import android.os.Looper
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import android.util.Log
import android.view.IRemoteAnimationFinishedCallback
import android.view.RemoteAnimationAdapter
import android.view.RemoteAnimationTarget
import android.view.SurfaceControl
+import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
+import com.android.wm.shell.startingsurface.StartingSurface
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertNull
import junit.framework.Assert.assertTrue
import junit.framework.AssertionFailedError
+import kotlin.concurrent.thread
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -37,7 +41,6 @@
import org.mockito.Mockito.verify
import org.mockito.Spy
import org.mockito.junit.MockitoJUnit
-import kotlin.concurrent.thread
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -47,13 +50,15 @@
@Mock lateinit var keyguardHandler: ActivityLaunchAnimator.KeyguardHandler
@Spy private val controller = TestLaunchAnimatorController(launchContainer)
@Mock lateinit var iCallback: IRemoteAnimationFinishedCallback
+ @Mock lateinit var startingSurface: StartingSurface
+ @Mock lateinit var failHandler: Log.TerribleFailureHandler
private lateinit var activityLaunchAnimator: ActivityLaunchAnimator
@get:Rule val rule = MockitoJUnit.rule()
@Before
fun setup() {
- activityLaunchAnimator = ActivityLaunchAnimator(keyguardHandler, mContext)
+ activityLaunchAnimator = ActivityLaunchAnimator(keyguardHandler, startingSurface, mContext)
}
private fun startIntentWithAnimation(
@@ -117,7 +122,7 @@
@Test
fun animatesIfActivityIsAlreadyOpenAndIsOnKeyguard() {
`when`(keyguardHandler.isOnKeyguard()).thenReturn(true)
- val animator = ActivityLaunchAnimator(keyguardHandler, context)
+ val animator = ActivityLaunchAnimator(keyguardHandler, startingSurface, context)
val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java)
var animationAdapter: RemoteAnimationAdapter? = null
@@ -175,6 +180,13 @@
verify(controller).onLaunchAnimationStart(anyBoolean())
}
+ @Test
+ fun controllerFromOrphanViewReturnsNullAndIsATerribleFailure() {
+ Log.setWtfHandler(failHandler)
+ assertNull(ActivityLaunchAnimator.Controller.fromView(View(mContext)))
+ verify(failHandler).onTerribleFailure(any(), any(), anyBoolean())
+ }
+
private fun fakeWindow(): RemoteAnimationTarget {
val bounds = Rect(10 /* left */, 20 /* top */, 30 /* right */, 40 /* bottom */)
val taskInfo = ActivityManager.RunningTaskInfo()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
new file mode 100644
index 0000000..8cba25d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.animation
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.widget.LinearLayout
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class GhostedViewLaunchAnimatorControllerTest : SysuiTestCase() {
+ @Test
+ fun animatingOrphanViewDoesNotCrash() {
+ val ghostedView = LinearLayout(mContext)
+ val controller = GhostedViewLaunchAnimatorController(ghostedView)
+ val state = ActivityLaunchAnimator.State(top = 0, bottom = 0, left = 0, right = 0)
+
+ controller.onIntentStarted(willAnimate = true)
+ controller.onLaunchAnimationStart(isExpandingFullyAbove = true)
+ controller.onLaunchAnimationProgress(state, progress = 0f, linearProgress = 0f)
+ controller.onLaunchAnimationEnd(isExpandingFullyAbove = true)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
index 546038e..b2a9e82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
@@ -39,7 +39,6 @@
import com.android.internal.logging.testing.FakeMetricsLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingDataProvider.GestureFinalizedListener;
-import com.android.systemui.dock.DockManagerFake;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -62,7 +61,6 @@
private BrightLineFalsingManager mBrightLineFalsingManager;
@Mock
private FalsingDataProvider mFalsingDataProvider;
- private final DockManagerFake mDockManager = new DockManagerFake();
private final MetricsLogger mMetricsLogger = new FakeMetricsLogger();
private final Set<FalsingClassifier> mClassifiers = new HashSet<>();
@Mock
@@ -102,7 +100,7 @@
mClassifiers.add(mClassifierB);
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
when(mKeyguardStateController.isShowing()).thenReturn(true);
- mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mDockManager,
+ mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider,
mMetricsLogger, mClassifiers, mSingleTapClassfier, mDoubleTapClassifier,
mHistoryTracker, mKeyguardStateController, mAccessibilityManager,
false);
@@ -168,7 +166,7 @@
// Even when the classifiers report a false, we should allow.
when(mClassifierA.classifyGesture(anyInt(), anyDouble(), anyDouble()))
.thenReturn(mPassedResult);
- mDockManager.setIsDocked(true);
+ when(mFalsingDataProvider.isDocked()).thenReturn(true);
assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
index 86243b5..c4f480d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
@@ -32,7 +32,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.testing.FakeMetricsLogger;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dock.DockManagerFake;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
@@ -52,7 +51,6 @@
private BrightLineFalsingManager mBrightLineFalsingManager;
@Mock
private FalsingDataProvider mFalsingDataProvider;
- private final DockManagerFake mDockManager = new DockManagerFake();
private final MetricsLogger mMetricsLogger = new FakeMetricsLogger();
private final Set<FalsingClassifier> mClassifiers = new HashSet<>();
@Mock
@@ -84,7 +82,7 @@
mClassifiers.add(mClassifierA);
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
when(mKeyguardStateController.isShowing()).thenReturn(true);
- mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mDockManager,
+ mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider,
mMetricsLogger, mClassifiers, mSingleTapClassifier, mDoubleTapClassifier,
mHistoryTracker, mKeyguardStateController, mAccessibilityManager,
false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
index 7d6ff34..5fa7214 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
@@ -19,30 +19,35 @@
import android.util.DisplayMetrics;
import android.view.MotionEvent;
-import com.android.systemui.utils.leaks.FakeBatteryController;
-import com.android.systemui.utils.leaks.LeakCheckedTest;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dock.DockManagerFake;
+import com.android.systemui.statusbar.policy.BatteryController;
import org.junit.After;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
-public class ClassifierTest extends LeakCheckedTest {
+public class ClassifierTest extends SysuiTestCase {
private FalsingDataProvider mDataProvider;
- private List<MotionEvent> mMotionEvents = new ArrayList<>();
+ private final List<MotionEvent> mMotionEvents = new ArrayList<>();
private float mOffsetX = 0;
private float mOffsetY = 0;
- private FakeBatteryController mFakeBatteryController;
+ @Mock
+ private BatteryController mBatteryController;
+ private final DockManagerFake mDockManager = new DockManagerFake();
public void setup() {
+ MockitoAnnotations.initMocks(this);
DisplayMetrics displayMetrics = new DisplayMetrics();
displayMetrics.xdpi = 100;
displayMetrics.ydpi = 100;
displayMetrics.widthPixels = 1000;
displayMetrics.heightPixels = 1000;
- mFakeBatteryController = new FakeBatteryController(getLeakCheck());
- mDataProvider = new FalsingDataProvider(displayMetrics, mFakeBatteryController);
+ mDataProvider = new FalsingDataProvider(displayMetrics, mBatteryController, mDockManager);
}
@After
@@ -54,10 +59,6 @@
return mDataProvider;
}
- FakeBatteryController getFakeBatteryController() {
- return mFakeBatteryController;
- }
-
protected void setOffsetX(float offsetX) {
mOffsetX = offsetX;
}
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 3c41216..d99a553 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
@@ -32,9 +32,12 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dock.DockManager;
+import com.android.systemui.dock.DockManagerFake;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.sensors.ProximitySensor;
@@ -67,6 +70,9 @@
private SysuiStatusBarStateController mStatusBarStateController;
@Mock
private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private BatteryController mBatteryController;
+ private final DockManagerFake mDockManager = new DockManagerFake();
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private final FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
@@ -79,8 +85,8 @@
mFalsingCollector = new FalsingCollectorImpl(mFalsingDataProvider, mFalsingManager,
mKeyguardUpdateMonitor, mHistoryTracker, mProximitySensor,
- mStatusBarStateController, mKeyguardStateController, mFakeExecutor,
- mFakeSystemClock);
+ mStatusBarStateController, mKeyguardStateController, mBatteryController,
+ mDockManager, mFakeExecutor, mFakeSystemClock);
}
@Test
@@ -91,9 +97,32 @@
@Test
public void testNoProximityWhenWirelessCharging() {
- when(mFalsingDataProvider.isWirelessCharging()).thenReturn(true);
- mFalsingCollector.onScreenTurningOn();
- verify(mProximitySensor, never()).register(any(ThresholdSensor.Listener.class));
+ ArgumentCaptor<BatteryController.BatteryStateChangeCallback> batteryCallbackCaptor =
+ ArgumentCaptor.forClass(BatteryController.BatteryStateChangeCallback.class);
+ verify(mBatteryController).addCallback(batteryCallbackCaptor.capture());
+ batteryCallbackCaptor.getValue().onWirelessChargingChanged(true);
+ verify(mProximitySensor).pause();
+ }
+
+ @Test
+ public void testProximityWhenOffWirelessCharging() {
+ ArgumentCaptor<BatteryController.BatteryStateChangeCallback> batteryCallbackCaptor =
+ ArgumentCaptor.forClass(BatteryController.BatteryStateChangeCallback.class);
+ verify(mBatteryController).addCallback(batteryCallbackCaptor.capture());
+ batteryCallbackCaptor.getValue().onWirelessChargingChanged(false);
+ verify(mProximitySensor).resume();
+ }
+
+ @Test
+ public void testNoProximityWhenDocked() {
+ mDockManager.setDockEvent(DockManager.STATE_DOCKED);
+ verify(mProximitySensor).pause();
+ }
+
+ @Test
+ public void testProximityWhenUndocked() {
+ mDockManager.setDockEvent(DockManager.STATE_NONE);
+ verify(mProximitySensor).resume();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
index 1fe694e..5dc607f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
import android.util.DisplayMetrics;
@@ -30,12 +31,15 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.classifier.FalsingDataProvider.GestureFinalizedListener;
-import com.android.systemui.utils.leaks.FakeBatteryController;
+import com.android.systemui.dock.DockManagerFake;
+import com.android.systemui.statusbar.policy.BatteryController;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.List;
@@ -43,19 +47,21 @@
@RunWith(AndroidTestingRunner.class)
public class FalsingDataProviderTest extends ClassifierTest {
- private FakeBatteryController mFakeBatteryController;
private FalsingDataProvider mDataProvider;
+ @Mock
+ private BatteryController mBatteryController;
+ private final DockManagerFake mDockManager = new DockManagerFake();
@Before
public void setup() {
super.setup();
- mFakeBatteryController = new FakeBatteryController(getLeakCheck());
+ MockitoAnnotations.initMocks(this);
DisplayMetrics displayMetrics = new DisplayMetrics();
displayMetrics.xdpi = 100;
displayMetrics.ydpi = 100;
displayMetrics.widthPixels = 1000;
displayMetrics.heightPixels = 1000;
- mDataProvider = new FalsingDataProvider(displayMetrics, mFakeBatteryController);
+ mDataProvider = new FalsingDataProvider(displayMetrics, mBatteryController, mDockManager);
}
@After
@@ -250,10 +256,17 @@
@Test
public void test_isWirelessCharging() {
- assertThat(mDataProvider.isWirelessCharging()).isFalse();
+ assertThat(mDataProvider.isDocked()).isFalse();
- mFakeBatteryController.setWirelessCharging(true);
- assertThat(mDataProvider.isWirelessCharging()).isTrue();
+ when(mBatteryController.isWirelessCharging()).thenReturn(true);
+ assertThat(mDataProvider.isDocked()).isTrue();
+ }
+
+ @Test
+ public void test_isDocked() {
+ assertThat(mDataProvider.isDocked()).isFalse();
+ mDockManager.setIsDocked(true);
+ assertThat(mDataProvider.isDocked()).isTrue();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
index b991976..a6ff2e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
@@ -59,7 +59,16 @@
final View view = new View(mContext);
mRotationButton = mock(RotationButton.class);
mRotationButtonController = new RotationButtonController(mContext, 0, 0);
- mRotationButtonController.setRotationButton(mRotationButton, (visibility) -> {});
+ mRotationButtonController.setRotationButton(mRotationButton,
+ new RotationButton.RotationButtonUpdatesCallback() {
+ @Override
+ public void onVisibilityChanged(boolean isVisible) {
+ }
+
+ @Override
+ public void onPositionChanged() {
+ }
+ });
// Due to a mockito issue, only spy the object after setting the initial state
mRotationButtonController = spy(mRotationButtonController);
doReturn(view).when(mRotationButton).getCurrentView();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt
new file mode 100644
index 0000000..0a20001
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt
@@ -0,0 +1,127 @@
+package com.android.systemui.navigationbar.gestural
+
+import android.view.Gravity
+import android.view.Surface
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.navigationbar.gestural.FloatingRotationButtonPositionCalculator.Position
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@SmallTest
+internal class FloatingRotationButtonPositionCalculatorTest(private val testCase: TestCase)
+ : SysuiTestCase() {
+
+ private val calculator = FloatingRotationButtonPositionCalculator(
+ MARGIN_DEFAULT, MARGIN_TASKBAR_LEFT, MARGIN_TASKBAR_BOTTOM
+ )
+
+ @Test
+ fun calculatePosition() {
+ val position = calculator.calculatePosition(
+ testCase.rotation,
+ testCase.taskbarVisible,
+ testCase.taskbarStashed
+ )
+
+ assertThat(position).isEqualTo(testCase.expectedPosition)
+ }
+
+ internal class TestCase(
+ val rotation: Int,
+ val taskbarVisible: Boolean,
+ val taskbarStashed: Boolean,
+ val expectedPosition: Position
+ ) {
+ override fun toString(): String =
+ "when rotation = $rotation, " +
+ "taskbarVisible = $taskbarVisible, " +
+ "taskbarStashed = $taskbarStashed - " +
+ "expected $expectedPosition"
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<TestCase> =
+ listOf(
+ TestCase(
+ rotation = Surface.ROTATION_0,
+ taskbarVisible = false,
+ taskbarStashed = false,
+ expectedPosition = Position(
+ gravity = Gravity.BOTTOM or Gravity.LEFT,
+ translationX = MARGIN_DEFAULT,
+ translationY = -MARGIN_DEFAULT
+ )
+ ),
+ TestCase(
+ rotation = Surface.ROTATION_90,
+ taskbarVisible = false,
+ taskbarStashed = false,
+ expectedPosition = Position(
+ gravity = Gravity.BOTTOM or Gravity.RIGHT,
+ translationX = -MARGIN_DEFAULT,
+ translationY = -MARGIN_DEFAULT
+ )
+ ),
+ TestCase(
+ rotation = Surface.ROTATION_180,
+ taskbarVisible = false,
+ taskbarStashed = false,
+ expectedPosition = Position(
+ gravity = Gravity.TOP or Gravity.RIGHT,
+ translationX = -MARGIN_DEFAULT,
+ translationY = MARGIN_DEFAULT
+ )
+ ),
+ TestCase(
+ rotation = Surface.ROTATION_270,
+ taskbarVisible = false,
+ taskbarStashed = false,
+ expectedPosition = Position(
+ gravity = Gravity.TOP or Gravity.LEFT,
+ translationX = MARGIN_DEFAULT,
+ translationY = MARGIN_DEFAULT
+ )
+ ),
+ TestCase(
+ rotation = Surface.ROTATION_0,
+ taskbarVisible = true,
+ taskbarStashed = false,
+ expectedPosition = Position(
+ gravity = Gravity.BOTTOM or Gravity.LEFT,
+ translationX = MARGIN_TASKBAR_LEFT,
+ translationY = -MARGIN_TASKBAR_BOTTOM
+ )
+ ),
+ TestCase(
+ rotation = Surface.ROTATION_0,
+ taskbarVisible = true,
+ taskbarStashed = true,
+ expectedPosition = Position(
+ gravity = Gravity.BOTTOM or Gravity.LEFT,
+ translationX = MARGIN_DEFAULT,
+ translationY = -MARGIN_DEFAULT
+ )
+ ),
+ TestCase(
+ rotation = Surface.ROTATION_90,
+ taskbarVisible = true,
+ taskbarStashed = false,
+ expectedPosition = Position(
+ gravity = Gravity.BOTTOM or Gravity.RIGHT,
+ translationX = -MARGIN_TASKBAR_LEFT,
+ translationY = -MARGIN_TASKBAR_BOTTOM
+ )
+ )
+ )
+
+ private const val MARGIN_DEFAULT = 10
+ private const val MARGIN_TASKBAR_LEFT = 20
+ private const val MARGIN_TASKBAR_BOTTOM = 30
+ }
+}
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 05bef4c..24c189a 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
@@ -1125,7 +1125,8 @@
new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A));
when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(channel);
PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A);
- PeopleSpaceTile tile = mManager.getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT);
+ PeopleSpaceTile tile = mManager
+ .getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT, true);
assertThat(tile.getId()).isEqualTo(key.getShortcutId());
}
@@ -1133,7 +1134,8 @@
public void testGetPeopleTileFromPersistentStorageNoConversation() throws Exception {
when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(null);
PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A);
- PeopleSpaceTile tile = mManager.getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT);
+ PeopleSpaceTile tile = mManager
+ .getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT, false);
assertThat(tile).isNull();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
index c2bd024f..84776c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
@@ -148,8 +148,10 @@
eq(true) /* in */, any());
clearInvocations(mQsDetail.mClipper);
+ // Detail adapters should always animate on close. shouldAnimate() should only affect the
+ // open transition
mQsDetail.handleShowingDetail(null, 0, 0, false);
- verify(mQsDetail.mClipper).updateCircularClip(eq(false) /* animate */, anyInt(), anyInt(),
+ verify(mQsDetail.mClipper).updateCircularClip(eq(true) /* animate */, anyInt(), anyInt(),
eq(false) /* in */, any());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 21c6292..d5a2919 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -33,6 +33,7 @@
import android.hardware.biometrics.PromptInfo;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.os.Bundle;
+import android.view.InsetsState;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -124,24 +125,25 @@
public void testOnSystemBarAttributesChanged() {
doTestOnSystemBarAttributesChanged(DEFAULT_DISPLAY, 1,
new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false,
- BEHAVIOR_DEFAULT, false);
+ BEHAVIOR_DEFAULT, new InsetsState(), "test");
}
@Test
public void testOnSystemBarAttributesChangedForSecondaryDisplay() {
doTestOnSystemBarAttributesChanged(SECONDARY_DISPLAY, 1,
new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false,
- BEHAVIOR_DEFAULT, false);
+ BEHAVIOR_DEFAULT, new InsetsState(), "test");
}
private void doTestOnSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, boolean isFullscreen) {
+ @Behavior int behavior, InsetsState requestedState, String packageName) {
mCommandQueue.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
- navbarColorManagedByIme, behavior, isFullscreen);
+ navbarColorManagedByIme, behavior, requestedState, packageName);
waitForIdleSync();
verify(mCallbacks).onSystemBarAttributesChanged(eq(displayId), eq(appearance),
- eq(appearanceRegions), eq(navbarColorManagedByIme), eq(behavior), eq(isFullscreen));
+ eq(appearanceRegions), eq(navbarColorManagedByIme), eq(behavior),
+ eq(requestedState), eq(packageName));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index 7c819f5..85ea52b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -39,6 +39,7 @@
import android.graphics.Color;
import android.graphics.drawable.Icon;
import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -131,4 +132,19 @@
icon, 0, 0, "");
assertFalse(mIconView.set(largeIcon));
}
+
+ @Test
+ public void testNullNotifInfo() {
+ Bitmap bitmap = Bitmap.createBitmap(60, 60, Bitmap.Config.ARGB_8888);
+ Icon icon = Icon.createWithBitmap(bitmap);
+ StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage",
+ icon, 0, 0, "");
+ mIconView.setNotification(mock(StatusBarNotification.class));
+ mIconView.getIcon(largeIcon);
+ // no crash? good
+
+ mIconView.setNotification(null);
+ mIconView.getIcon(largeIcon);
+ // no crash? good
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index b03df880..3f35063 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -63,7 +63,6 @@
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.FooterView;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.KeyguardBypassEnabledProvider;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -101,7 +100,6 @@
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@Mock private RemoteInputController mRemoteInputController;
@Mock private NotificationRoundnessManager mNotificationRoundnessManager;
- @Mock private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider;
@Mock private KeyguardBypassController mBypassController;
@Mock private NotificationSectionsManager mNotificationSectionsManager;
@Mock private NotificationSection mNotificationSection;
@@ -150,8 +148,7 @@
mAmbientState,
mFeatureFlags,
mUnlockedScreenOffAnimationController);
- mStackScrollerInternal.initView(getContext(), mKeyguardBypassEnabledProvider,
- mNotificationSwipeHelper);
+ mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper);
mStackScroller = spy(mStackScrollerInternal);
mStackScroller.setShelfController(notificationShelfController);
mStackScroller.setStatusBar(mBar);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
index cdfab1e..c3adee9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
@@ -102,7 +102,8 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- false /* isFullscreen */);
+ null /* requestedState */,
+ null /* packageName */);
assertTrue(mLightsOutNotifController.areLightsOut());
}
@@ -114,7 +115,8 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- false /* isFullscreen */);
+ null /* requestedState */,
+ null /* packageName */);
assertFalse(mLightsOutNotifController.areLightsOut());
}
@@ -144,7 +146,8 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- false /* isFullscreen */);
+ null /* requestedState */,
+ null /* packageName */);
// THEN we should show dot
assertTrue(mLightsOutNotifController.shouldShowDot());
@@ -163,7 +166,8 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- false /* isFullscreen */);
+ null /* requestedState */,
+ null /* packageName */);
// THEN we shouldn't show the dot
assertFalse(mLightsOutNotifController.shouldShowDot());
@@ -182,7 +186,8 @@
null /* appearanceRegions */,
false /* navbarColorManagedByIme */,
BEHAVIOR_DEFAULT,
- false /* isFullscreen */);
+ null /* requestedState */,
+ null /* packageName */);
// THEN we shouldn't show the dot
assertFalse(mLightsOutNotifController.shouldShowDot());
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 1540b14..3f9ea18 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
@@ -97,6 +97,7 @@
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.qs.QSDetailDisplayer;
+import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardAffordanceView;
@@ -283,6 +284,8 @@
@Mock
private SecureSettings mSecureSettings;
@Mock
+ private SplitShadeHeaderController mSplitShadeHeaderController;
+ @Mock
private ContentResolver mContentResolver;
@Mock
private TapAgainViewController mTapAgainViewController;
@@ -298,6 +301,8 @@
private NotificationRemoteInputManager mNotificationRemoteInputManager;
@Mock
private RemoteInputController mRemoteInputController;
+ @Mock
+ private RecordingController mRecordingController;
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -436,8 +441,10 @@
mFragmentService,
mContentResolver,
mQuickAccessWalletController,
+ mRecordingController,
new FakeExecutor(new FakeSystemClock()),
mSecureSettings,
+ mSplitShadeHeaderController,
mUnlockedScreenOffAnimationController,
mNotificationRemoteInputManager);
mNotificationPanelViewController.initDependencies(
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 cbc7c6d..f126ed0 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
@@ -152,6 +152,7 @@
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+import com.android.wm.shell.startingsurface.StartingSurface;
import org.junit.Before;
import org.junit.Test;
@@ -273,6 +274,7 @@
@Mock private IWallpaperManager mWallpaperManager;
@Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+ @Mock private StartingSurface mStartingSurface;
private ShadeController mShadeController;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private InitController mInitController = new InitController();
@@ -443,7 +445,8 @@
mLockscreenTransitionController,
mFeatureFlags,
mKeyguardUnlockAnimationController,
- mUnlockedScreenOffAnimationController);
+ mUnlockedScreenOffAnimationController,
+ Optional.of(mStartingSurface));
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/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 1a24c11..07d3fc2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -466,6 +466,44 @@
}
@Test
+ public void catchException_whenPackageNameIsOverlayName() {
+ mDeviceProvisionedController = mock(DeviceProvisionedController.class);
+ mThemeOverlayApplier = mock(ThemeOverlayApplier.class);
+ mWallpaperManager = mock(WallpaperManager.class);
+
+ // Assume we have some wallpaper colors at boot.
+ when(mWallpaperManager.getWallpaperColors(anyInt()))
+ .thenReturn(new WallpaperColors(Color.valueOf(Color.GRAY), null, null));
+
+ Executor executor = MoreExecutors.directExecutor();
+
+ mThemeOverlayController = new ThemeOverlayController(null /* context */,
+ mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier,
+ mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
+ mUserTracker, mDumpManager, mFeatureFlags, mWakefulnessLifecycle) {
+ @Nullable
+ @Override
+ protected FabricatedOverlay getOverlay(int color, int type) {
+ FabricatedOverlay overlay = mock(FabricatedOverlay.class);
+ when(overlay.getIdentifier())
+ .thenReturn(new OverlayIdentifier("com.thebest.livewallpaperapp.ever"));
+
+ return overlay;
+ }
+
+ };
+ mThemeOverlayController.start();
+
+ verify(mWallpaperManager).addOnColorsChangedListener(mColorsListener.capture(), eq(null),
+ eq(UserHandle.USER_ALL));
+ verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture());
+
+ // Colors were applied during controller initialization.
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ clearInvocations(mThemeOverlayApplier);
+ }
+
+ @Test
public void onWallpaperColorsChanged_defersUntilSetupIsCompleted_ifHasColors() {
mDeviceProvisionedController = mock(DeviceProvisionedController.class);
mThemeOverlayApplier = mock(ThemeOverlayApplier.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index 3cea175..dd4830e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -99,6 +99,8 @@
Prefs.putInt(mContext,
Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT,
VolumePrefs.SHOW_RINGER_TOAST_COUNT + 1);
+
+ Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, false);
}
private State createShellState() {
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index a48f76e..3047c90 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -268,6 +268,14 @@
// Package: android
NOTE_NAS_UPGRADE = 64;
+ // Notify the user to unblock the microphone global toggle
+ // Package: android
+ NOTE_UNBLOCK_MIC_TOGGLE = 65;
+
+ // Notify the user to unblock the camera global toggle
+ // Package: android
+ NOTE_UNBLOCK_CAM_TOGGLE = 66;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index b8ceffad..4127556 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -901,7 +901,7 @@
Set<String> sameOemPackageCerts = new HashSet<>();
// Assume OEM may enter same package name in the parallel string array with
- // multiple ADK certs corresponding to it
+ // multiple APK certs corresponding to it
for (int i = 0; i < oemPackages.length; i++) {
if (oemPackages[i].equals(packageName)) {
sameOemPackageCerts.add(sameOemCerts[i].replaceAll(":", ""));
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 8d96957..e4a30ad5 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -122,6 +122,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FunctionalUtils;
@@ -260,7 +261,7 @@
* <Package, User> -> list of suppressor tokens
*/
@GuardedBy("mLock")
- private ArrayMap<Pair<String, UserHandle>, ArrayList<IBinder>> mSuppressReminders =
+ private ArrayMap<Pair<Integer, UserHandle>, ArrayList<IBinder>> mSuppressReminders =
new ArrayMap<>();
private final ArrayMap<SensorUseReminderDialogInfo, ArraySet<Integer>>
@@ -423,7 +424,7 @@
}
synchronized (mLock) {
- if (mSuppressReminders.containsKey(new Pair<>(packageName, user))) {
+ if (mSuppressReminders.containsKey(new Pair<>(sensor, user))) {
Log.d(TAG,
"Suppressed sensor privacy reminder for " + packageName + "/" + user);
return;
@@ -450,14 +451,22 @@
for (int taskNum = 0; taskNum < numTasks; taskNum++) {
RunningTaskInfo task = tasks.get(taskNum);
- if (task.isVisible && task.topActivity.getPackageName().equals(packageName)) {
- if (task.isFocused) {
- // There is the one focused activity
- enqueueSensorUseReminderDialogAsync(task.taskId, user, packageName, sensor);
- return;
- }
+ if (task.isVisible) {
+ if (task.topActivity.getPackageName().equals(packageName)) {
+ if (task.isFocused) {
+ // There is the one focused activity
+ enqueueSensorUseReminderDialogAsync(task.taskId, user, packageName,
+ sensor);
+ return;
+ }
- tasksOfPackageUsingSensor.add(task);
+ tasksOfPackageUsingSensor.add(task);
+ } else if (task.topActivity.flattenToString().equals(mContext.getResources()
+ .getString(R.string.config_sensorUseStartedActivity))
+ && task.isFocused) {
+ enqueueSensorUseReminderDialogAsync(task.taskId, user, packageName,
+ sensor);
+ }
}
}
@@ -550,8 +559,15 @@
SensorUseReminderDialogInfo info =
new SensorUseReminderDialogInfo(taskId, user, packageName);
if (!mQueuedSensorUseReminderDialogs.containsKey(info)) {
- ArraySet<Integer> sensors = new ArraySet<Integer>();
- sensors.add(sensor);
+ ArraySet<Integer> sensors = new ArraySet<>();
+ if (sensor == MICROPHONE && mSuppressReminders.containsKey(new Pair<>(CAMERA, user))
+ || sensor == CAMERA && mSuppressReminders
+ .containsKey(new Pair<>(MICROPHONE, user))) {
+ sensors.add(MICROPHONE);
+ sensors.add(CAMERA);
+ } else {
+ sensors.add(sensor);
+ }
mQueuedSensorUseReminderDialogs.put(info, sensors);
mHandler.sendMessageDelayed(
PooledLambda.obtainMessage(this::showSensorUserReminderDialog, info),
@@ -608,6 +624,7 @@
@NonNull String packageName, int sensor) {
int iconRes;
int messageRes;
+ int notificationId;
CharSequence packageLabel;
try {
@@ -622,9 +639,11 @@
if (sensor == MICROPHONE) {
iconRes = R.drawable.ic_mic_blocked;
messageRes = R.string.sensor_privacy_start_use_mic_notification_content_title;
+ notificationId = SystemMessage.NOTE_UNBLOCK_MIC_TOGGLE;
} else {
iconRes = R.drawable.ic_camera_blocked;
messageRes = R.string.sensor_privacy_start_use_camera_notification_content_title;
+ notificationId = SystemMessage.NOTE_UNBLOCK_CAM_TOGGLE;
}
NotificationManager notificationManager =
@@ -641,7 +660,7 @@
notificationManager.createNotificationChannel(channel);
Icon icon = Icon.createWithResource(getUiContext().getResources(), iconRes);
- notificationManager.notify(sensor,
+ notificationManager.notify(notificationId,
new Notification.Builder(mContext, SENSOR_PRIVACY_CHANNEL_ID)
.setContentTitle(getUiContext().getString(messageRes))
.setContentText(Html.fromHtml(getUiContext().getString(
@@ -1161,13 +1180,12 @@
}
@Override
- public void suppressIndividualSensorPrivacyReminders(int userId, String packageName,
+ public void suppressIndividualSensorPrivacyReminders(int userId, int sensor,
IBinder token, boolean suppress) {
enforceManageSensorPrivacyPermission();
- Objects.requireNonNull(packageName);
Objects.requireNonNull(token);
- Pair<String, UserHandle> key = new Pair<>(packageName, UserHandle.of(userId));
+ Pair<Integer, UserHandle> key = new Pair<>(sensor, UserHandle.of(userId));
synchronized (mLock) {
if (suppress) {
@@ -1197,7 +1215,7 @@
* @param key Key the token is in
* @param token The token to remove
*/
- private void removeSuppressPackageReminderToken(@NonNull Pair<String, UserHandle> key,
+ private void removeSuppressPackageReminderToken(@NonNull Pair<Integer, UserHandle> key,
@NonNull IBinder token) {
synchronized (mLock) {
ArrayList<IBinder> suppressPackageReminderTokens =
@@ -1229,7 +1247,7 @@
@Override
public void binderDied(@NonNull IBinder token) {
synchronized (mLock) {
- for (Pair<String, UserHandle> key : mSuppressReminders.keySet()) {
+ for (Pair<Integer, UserHandle> key : mSuppressReminders.keySet()) {
removeSuppressPackageReminderToken(key, token);
}
}
@@ -1557,7 +1575,7 @@
listeners.finishBroadcast();
}
- public void removeSuppressPackageReminderToken(Pair<String, UserHandle> key,
+ public void removeSuppressPackageReminderToken(Pair<Integer, UserHandle> key,
IBinder token) {
sendMessage(PooledLambda.obtainMessage(
SensorPrivacyServiceImpl::removeSuppressPackageReminderToken,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bce46f5..9a77ec5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3458,30 +3458,39 @@
final long callingId = Binder.clearCallingIdentity();
try {
IPackageManager pm = AppGlobals.getPackageManager();
+ boolean permitted = true;
// Instant packages are not protected
if (getPackageManagerInternal().isPackageDataProtected(
resolvedUserId, packageName)) {
- throw new SecurityException(
- "Cannot clear data for a protected package: " + packageName);
+ if (ActivityManager.checkUidPermission(android.Manifest.permission.MANAGE_USERS,
+ uid) == PERMISSION_GRANTED) {
+ // The caller has the MANAGE_USERS permission, tell them what's going on.
+ throw new SecurityException(
+ "Cannot clear data for a protected package: " + packageName);
+ } else {
+ permitted = false; // fall through and throw the SecurityException below.
+ }
}
ApplicationInfo applicationInfo = null;
- try {
- applicationInfo = pm.getApplicationInfo(packageName,
- MATCH_UNINSTALLED_PACKAGES, resolvedUserId);
- } catch (RemoteException e) {
- /* ignore */
+ if (permitted) {
+ try {
+ applicationInfo = pm.getApplicationInfo(packageName,
+ MATCH_UNINSTALLED_PACKAGES, resolvedUserId);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ permitted = (applicationInfo != null && applicationInfo.uid == uid) // own uid data
+ || (checkComponentPermission(permission.CLEAR_APP_USER_DATA,
+ pid, uid, -1, true) == PackageManager.PERMISSION_GRANTED);
}
- appInfo = applicationInfo;
- final boolean clearingOwnUidData = appInfo != null && appInfo.uid == uid;
-
- if (!clearingOwnUidData && checkComponentPermission(permission.CLEAR_APP_USER_DATA,
- pid, uid, -1, true) != PackageManager.PERMISSION_GRANTED) {
+ if (!permitted) {
throw new SecurityException("PID " + pid + " does not have permission "
+ android.Manifest.permission.CLEAR_APP_USER_DATA + " to clear data"
+ " of package " + packageName);
}
+ appInfo = applicationInfo;
final boolean hasInstantMetadata = getPackageManagerInternal()
.hasInstantApplicationMetadata(packageName, resolvedUserId);
@@ -12458,6 +12467,15 @@
return sticky;
}
+ // SafetyNet logging for b/177931370. If any process other than system_server tries to
+ // listen to this broadcast action, then log it.
+ if (callingPid != Process.myPid()) {
+ if (filter.hasAction("com.android.server.net.action.SNOOZE_WARNING")
+ || filter.hasAction("com.android.server.net.action.SNOOZE_RAPID")) {
+ EventLog.writeEvent(0x534e4554, "177931370", callingUid, "");
+ }
+ }
+
synchronized (this) {
IApplicationThread thread;
if (callerApp != null && ((thread = callerApp.getThread()) == null
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 67dfb80..0c633ca 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -579,8 +579,10 @@
}
}
- // Collect the latest low power stats without holding the mStats lock.
- mStats.fillLowPowerStats();
+ if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RPM) != 0) {
+ // Collect the latest low power stats without holding the mStats lock.
+ mStats.fillLowPowerStats();
+ }
final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
final BluetoothActivityEnergyInfo bluetoothInfo = awaitControllerInfo(bluetoothReceiver);
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index d6bf8db..93d5c06b 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -256,7 +256,7 @@
@GuardedBy("mService")
private boolean mPendingFullOomAdjUpdate = false;
- private final PlatformCompatCache mPlatformCompatCache;
+ final PlatformCompatCache mPlatformCompatCache;
/** Overrideable by a test */
@VisibleForTesting
@@ -309,6 +309,12 @@
}
}
+ void onApplicationInfoChanged(ApplicationInfo app) {
+ for (int i = mCaches.size() - 1; i >= 0; i--) {
+ mCaches.valueAt(i).onApplicationInfoChanged(app);
+ }
+ }
+
static class CacheItem implements CompatChange.ChangeListener {
private final PlatformCompat mPlatformCompat;
private final long mChangeId;
@@ -328,22 +334,14 @@
final int index = mCache.indexOfKey(app.packageName);
Pair<Boolean, WeakReference<ApplicationInfo>> p;
if (index < 0) {
- p = new Pair<>(mPlatformCompat.isChangeEnabledInternalNoLogging(mChangeId,
- app),
- new WeakReference<>(app));
- mCache.put(app.packageName, p);
- return p.first;
+ return fetchLocked(app, index);
}
p = mCache.valueAt(index);
if (p.second.get() == app) {
return p.first;
}
// Cache is invalid, regenerate it
- p = new Pair<>(mPlatformCompat.isChangeEnabledInternalNoLogging(mChangeId,
- app),
- new WeakReference<>(app));
- mCache.setValueAt(index, p);
- return p.first;
+ return fetchLocked(app, index);
}
}
@@ -353,10 +351,40 @@
}
}
+ @GuardedBy("mLock")
+ boolean fetchLocked(ApplicationInfo app, int index) {
+ final Pair<Boolean, WeakReference<ApplicationInfo>> p = new Pair<>(
+ mPlatformCompat.isChangeEnabledInternalNoLogging(mChangeId, app),
+ new WeakReference<>(app));
+ if (index >= 0) {
+ mCache.setValueAt(index, p);
+ } else {
+ mCache.put(app.packageName, p);
+ }
+ return p.first;
+ }
+
+ void onApplicationInfoChanged(ApplicationInfo app) {
+ synchronized (mLock) {
+ final int index = mCache.indexOfKey(app.packageName);
+ if (index >= 0) {
+ fetchLocked(app, index);
+ }
+ }
+ }
+
@Override
public void onCompatChange(String packageName) {
synchronized (mLock) {
- mCache.remove(packageName);
+ final int index = mCache.indexOfKey(packageName);
+ if (index >= 0) {
+ final ApplicationInfo app = mCache.valueAt(index).second.get();
+ if (app != null) {
+ fetchLocked(app, index);
+ } else {
+ mCache.removeAt(index);
+ }
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index b77270f..a97738f 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -4710,6 +4710,8 @@
if (ai != null) {
if (ai.packageName.equals(app.info.packageName)) {
app.info = ai;
+ mService.mOomAdjuster.mPlatformCompatCache
+ .onApplicationInfoChanged(ai);
}
app.getThread().scheduleApplicationInfoChanged(ai);
targetProcesses.add(app.getWindowProcessController());
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 7f1402d..db2ecc5 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -849,7 +849,7 @@
return DeviceConfig.getBoolean(
NAMESPACE_APP_HIBERNATION,
KEY_APP_HIBERNATION_ENABLED,
- false /* defaultValue */);
+ true /* defaultValue */);
}
/**
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 ca357b4c..f11fe8a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -188,18 +188,7 @@
mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
}
- protected boolean successHapticsEnabled() {
- return true;
- }
-
- protected boolean errorHapticsEnabled() {
- return true;
- }
-
protected final void vibrateSuccess() {
- if (!successHapticsEnabled()) {
- return;
- }
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
if (vibrator != null) {
vibrator.vibrate(SUCCESS_VIBRATION_EFFECT, VIBRATION_SONIFICATION_ATTRIBUTES);
@@ -207,9 +196,6 @@
}
protected final void vibrateError() {
- if (!errorHapticsEnabled()) {
- return;
- }
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
if (vibrator != null) {
vibrator.vibrate(ERROR_VIBRATION_EFFECT, VIBRATION_SONIFICATION_ATTRIBUTES);
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 db927b2..3757404 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,7 +19,6 @@
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;
@@ -33,7 +32,6 @@
import android.hardware.face.FaceManager;
import android.os.IBinder;
import android.os.RemoteException;
-import android.provider.Settings;
import android.util.Slog;
import com.android.internal.R;
@@ -59,9 +57,6 @@
@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;
@@ -92,10 +87,6 @@
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;
}
@NonNull
@@ -261,18 +252,4 @@
Slog.e(TAG, "Remote exception", e);
}
}
-
- @Override
- protected boolean successHapticsEnabled() {
- return mCustomHaptics
- ? Settings.Global.getInt(mContentResolver, "face_success_enabled", 1) == 0
- : super.successHapticsEnabled();
- }
-
- @Override
- protected boolean errorHapticsEnabled() {
- return mCustomHaptics
- ? Settings.Global.getInt(mContentResolver, "face_error_enabled", 1) == 0
- : super.errorHapticsEnabled();
- }
}
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 6c0adaf..c3de7aa 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,7 +17,6 @@
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;
@@ -28,7 +27,6 @@
import android.hardware.face.FaceManager;
import android.os.IBinder;
import android.os.RemoteException;
-import android.provider.Settings;
import android.util.Slog;
import com.android.internal.R;
@@ -49,8 +47,6 @@
private static final String TAG = "FaceAuthenticationClient";
- @NonNull private final ContentResolver mContentResolver;
- private final boolean mCustomHaptics;
private final UsageStats mUsageStats;
private final int[] mBiometricPromptIgnoreList;
@@ -81,10 +77,6 @@
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;
}
@NonNull
@@ -200,18 +192,4 @@
final boolean shouldSend = shouldSend(acquireInfo, vendorCode);
onAcquiredInternal(acquireInfo, vendorCode, shouldSend);
}
-
- @Override
- protected boolean successHapticsEnabled() {
- return mCustomHaptics
- ? Settings.Global.getInt(mContentResolver, "face_success_enabled", 1) == 0
- : super.successHapticsEnabled();
- }
-
- @Override
- protected boolean errorHapticsEnabled() {
- return mCustomHaptics
- ? Settings.Global.getInt(mContentResolver, "face_error_enabled", 1) == 0
- : super.errorHapticsEnabled();
- }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 6a05ed4..19134e4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskStackListener;
-import android.content.ContentResolver;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricFingerprintConstants;
@@ -30,7 +29,6 @@
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
import android.os.RemoteException;
-import android.provider.Settings;
import android.util.Slog;
import com.android.server.biometrics.Utils;
@@ -57,9 +55,6 @@
@Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
@Nullable private ICancellationSignal mCancellationSignal;
- @NonNull private final ContentResolver mContentResolver;
- private final boolean mCustomHaptics;
-
FingerprintAuthenticationClient(@NonNull Context context,
@NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
@@ -74,10 +69,6 @@
lockoutCache, allowBackgroundAuthentication);
mLockoutCache = lockoutCache;
mUdfpsOverlayController = udfpsOverlayController;
-
- mContentResolver = context.getContentResolver();
- mCustomHaptics = Settings.Global.getInt(mContentResolver,
- "fp_custom_success_error", 0) == 1;
}
@NonNull
@@ -213,18 +204,4 @@
UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
mCallback.onClientFinished(this, false /* success */);
}
-
- @Override
- protected boolean successHapticsEnabled() {
- return mCustomHaptics
- ? Settings.Global.getInt(mContentResolver, "fp_success_enabled", 1) == 0
- : super.successHapticsEnabled();
- }
-
- @Override
- protected boolean errorHapticsEnabled() {
- return mCustomHaptics
- ? Settings.Global.getInt(mContentResolver, "fp_error_enabled", 1) == 0
- : super.errorHapticsEnabled();
- }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index 45e93a0..5e1a245 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -30,13 +30,14 @@
import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.AcquisitionClient;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.DetectionConsumer;
import com.android.server.biometrics.sensors.fingerprint.UdfpsHelper;
/**
* Performs fingerprint detection without exposing any matching information (e.g. accept/reject
* have the same haptic, lockout counter is not increased).
*/
-class FingerprintDetectClient extends AcquisitionClient<ISession> {
+class FingerprintDetectClient extends AcquisitionClient<ISession> implements DetectionConsumer {
private static final String TAG = "FingerprintDetectClient";
@@ -88,7 +89,8 @@
}
}
- void onInteractionDetected() {
+ @Override
+ public void onInteractionDetected() {
vibrateSuccess();
try {
diff --git a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java
new file mode 100644
index 0000000..a81213d
--- /dev/null
+++ b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java
@@ -0,0 +1,383 @@
+/*
+ * 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.compat.overrides;
+
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
+
+import static java.util.Collections.emptyMap;
+import static java.util.Collections.emptySet;
+
+import android.app.compat.PackageOverride;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * A utility class for parsing App Compat Overrides flags.
+ *
+ * @hide
+ */
+final class AppCompatOverridesParser {
+ /**
+ * Flag for specifying all compat change IDs owned by a namespace. See {@link
+ * #parseOwnedChangeIds} for information on how this flag is parsed.
+ */
+ static final String FLAG_OWNED_CHANGE_IDS = "owned_change_ids";
+
+ /**
+ * Flag for immediately removing overrides for certain packages and change IDs (from the compat
+ * platform), as well as stopping to apply them, in case of an emergency. See {@link
+ * #parseRemoveOverrides} for information on how this flag is parsed.
+ */
+ static final String FLAG_REMOVE_OVERRIDES = "remove_overrides";
+
+ private static final String TAG = "AppCompatOverridesParser";
+
+ private static final String WILDCARD_SYMBOL = "*";
+
+ private static final Pattern BOOLEAN_PATTERN =
+ Pattern.compile("true|false", Pattern.CASE_INSENSITIVE);
+
+ private static final String WILDCARD_NO_OWNED_CHANGE_IDS_WARNING =
+ "Wildcard can't be used in '" + FLAG_REMOVE_OVERRIDES + "' flag with an empty "
+ + FLAG_OWNED_CHANGE_IDS + "' flag";
+
+ private final PackageManager mPackageManager;
+
+ AppCompatOverridesParser(PackageManager packageManager) {
+ mPackageManager = packageManager;
+ }
+
+ /**
+ * Parses the given {@code configStr} and returns a map from package name to a set of change
+ * IDs to remove for that package.
+ *
+ * <p>The given {@code configStr} is expected to either be:
+ *
+ * <ul>
+ * <li>'*' (wildcard), to indicate that all owned overrides, specified in {@code
+ * ownedChangeIds}, for all installed packages should be removed.
+ * <li>A comma separated key value list, where the key is a package name and the value is
+ * either:
+ * <ul>
+ * <li>'*' (wildcard), to indicate that all owned overrides, specified in {@code
+ * ownedChangeIds} for that package should be removed.
+ * <li>A colon separated list of change IDs to remove for that package.
+ * </ul>
+ * </ul>
+ *
+ * <p>If the given {@code configStr} doesn't match the expected format, an empty map will be
+ * returned. If a specific change ID isn't a valid long, it will be ignored.
+ */
+ Map<String, Set<Long>> parseRemoveOverrides(String configStr, Set<Long> ownedChangeIds) {
+ if (configStr.isEmpty()) {
+ return emptyMap();
+ }
+
+ Map<String, Set<Long>> result = new ArrayMap<>();
+ if (configStr.equals(WILDCARD_SYMBOL)) {
+ if (ownedChangeIds.isEmpty()) {
+ Slog.w(TAG, WILDCARD_NO_OWNED_CHANGE_IDS_WARNING);
+ return emptyMap();
+ }
+ List<ApplicationInfo> installedApps = mPackageManager.getInstalledApplications(
+ MATCH_ANY_USER);
+ for (ApplicationInfo appInfo : installedApps) {
+ result.put(appInfo.packageName, ownedChangeIds);
+ }
+ return result;
+ }
+
+ KeyValueListParser parser = new KeyValueListParser(',');
+ try {
+ parser.setString(configStr);
+ } catch (IllegalArgumentException e) {
+ Slog.w(
+ TAG,
+ "Invalid format in '" + FLAG_REMOVE_OVERRIDES + "' flag: " + configStr, e);
+ return emptyMap();
+ }
+ for (int i = 0; i < parser.size(); i++) {
+ String packageName = parser.keyAt(i);
+ String changeIdsStr = parser.getString(packageName, /* def= */ "");
+ if (changeIdsStr.equals(WILDCARD_SYMBOL)) {
+ if (ownedChangeIds.isEmpty()) {
+ Slog.w(TAG, WILDCARD_NO_OWNED_CHANGE_IDS_WARNING);
+ continue;
+ }
+ result.put(packageName, ownedChangeIds);
+ } else {
+ for (String changeIdStr : changeIdsStr.split(":")) {
+ try {
+ long changeId = Long.parseLong(changeIdStr);
+ result.computeIfAbsent(packageName, k -> new ArraySet<>()).add(changeId);
+ } catch (NumberFormatException e) {
+ Slog.w(
+ TAG,
+ "Invalid change ID in '" + FLAG_REMOVE_OVERRIDES + "' flag: "
+ + changeIdStr, e);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+
+ /**
+ * Parses the given {@code configStr}, that is expected to be a comma separated list of change
+ * IDs, into a set.
+ *
+ * <p>If any of the change IDs isn't a valid long, it will be ignored.
+ */
+ static Set<Long> parseOwnedChangeIds(String configStr) {
+ if (configStr.isEmpty()) {
+ return emptySet();
+ }
+
+ Set<Long> result = new ArraySet<>();
+ for (String changeIdStr : configStr.split(",")) {
+ try {
+ result.add(Long.parseLong(changeIdStr));
+ } catch (NumberFormatException e) {
+ Slog.w(TAG,
+ "Invalid change ID in '" + FLAG_OWNED_CHANGE_IDS + "' flag: " + changeIdStr,
+ e);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Parses the given {@code configStr}, that is expected to be a comma separated list of changes
+ * overrides, and returns a {@link PackageOverrides}.
+ *
+ * <p>Each change override is in the following format:
+ * '<change-id>:<min-version-code?>:<max-version-code?>:<enabled?>'. If <enabled> is empty,
+ * this indicates that any override for the specified change ID should be removed.
+ *
+ * <p>If there are multiple overrides that should be added with the same change ID, the one
+ * that best fits the given {@code versionCode} is added.
+ *
+ * <p>Any overrides whose change ID is in {@code changeIdsToSkip} are ignored.
+ *
+ * <p>If a change override entry in {@code configStr} is invalid, it will be ignored. If the
+ * same change ID is both added and removed, i.e., has a change override entry with an empty
+ * enabled and another with a non-empty enabled, the change ID will only be removed.
+ */
+ static PackageOverrides parsePackageOverrides(
+ String configStr, long versionCode, Set<Long> changeIdsToSkip) {
+ if (configStr.isEmpty()) {
+ return new PackageOverrides();
+ }
+ PackageOverrideComparator comparator = new PackageOverrideComparator(versionCode);
+ Map<Long, PackageOverride> overridesToAdd = new ArrayMap<>();
+ Set<Long> overridesToRemove = new ArraySet<>();
+ for (String overrideEntryString : configStr.split(",")) {
+ List<String> changeIdAndVersions = Arrays.asList(overrideEntryString.split(":", 4));
+ if (changeIdAndVersions.size() != 4) {
+ Slog.w(TAG, "Invalid change override entry: " + overrideEntryString);
+ continue;
+ }
+ long changeId;
+ try {
+ changeId = Long.parseLong(changeIdAndVersions.get(0));
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Invalid change ID in override entry: " + overrideEntryString, e);
+ continue;
+ }
+
+ if (changeIdsToSkip.contains(changeId)) {
+ continue;
+ }
+
+ String minVersionCodeStr = changeIdAndVersions.get(1);
+ String maxVersionCodeStr = changeIdAndVersions.get(2);
+
+ String enabledStr = changeIdAndVersions.get(3);
+ if (enabledStr.isEmpty()) {
+ if (!minVersionCodeStr.isEmpty() || !maxVersionCodeStr.isEmpty()) {
+ Slog.w(
+ TAG,
+ "min/max version code should be empty if enabled is empty: "
+ + overrideEntryString);
+ }
+ overridesToRemove.add(changeId);
+ continue;
+ }
+ if (!BOOLEAN_PATTERN.matcher(enabledStr).matches()) {
+ Slog.w(TAG, "Invalid enabled string in override entry: " + overrideEntryString);
+ continue;
+ }
+ boolean enabled = Boolean.parseBoolean(enabledStr);
+ PackageOverride.Builder overrideBuilder = new PackageOverride.Builder().setEnabled(
+ enabled);
+ try {
+ if (!minVersionCodeStr.isEmpty()) {
+ overrideBuilder.setMinVersionCode(Long.parseLong(minVersionCodeStr));
+ }
+ if (!maxVersionCodeStr.isEmpty()) {
+ overrideBuilder.setMaxVersionCode(Long.parseLong(maxVersionCodeStr));
+ }
+ } catch (NumberFormatException e) {
+ Slog.w(TAG,
+ "Invalid min/max version code in override entry: " + overrideEntryString,
+ e);
+ continue;
+ }
+
+ try {
+ PackageOverride override = overrideBuilder.build();
+ if (!overridesToAdd.containsKey(changeId)
+ || comparator.compare(override, overridesToAdd.get(changeId)) < 0) {
+ overridesToAdd.put(changeId, override);
+ }
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Failed to build PackageOverride", e);
+ }
+ }
+
+ for (Long changeId : overridesToRemove) {
+ if (overridesToAdd.containsKey(changeId)) {
+ Slog.w(
+ TAG,
+ "Change ID ["
+ + changeId
+ + "] is both added and removed in package override flag: "
+ + configStr);
+ overridesToAdd.remove(changeId);
+ }
+ }
+
+ return new PackageOverrides(overridesToAdd, overridesToRemove);
+ }
+
+ /**
+ * A container for a map from change ID to {@link PackageOverride} to add and a set of change
+ * IDs to remove overrides for.
+ *
+ * <p>The map of overrides to add and the set of overrides to remove are mutually exclusive.
+ */
+ static final class PackageOverrides {
+ public final Map<Long, PackageOverride> overridesToAdd;
+ public final Set<Long> overridesToRemove;
+
+ PackageOverrides() {
+ this(emptyMap(), emptySet());
+ }
+
+ PackageOverrides(Map<Long, PackageOverride> overridesToAdd, Set<Long> overridesToRemove) {
+ this.overridesToAdd = overridesToAdd;
+ this.overridesToRemove = overridesToRemove;
+ }
+ }
+
+ /**
+ * A {@link Comparator} that compares @link PackageOverride} instances with respect to a
+ * specified {@code versionCode} as follows:
+ *
+ * <ul>
+ * <li>Prefer the {@link PackageOverride} whose version range contains {@code versionCode}.
+ * <li>Otherwise, prefer the {@link PackageOverride} whose version range is closest to {@code
+ * versionCode} from below.
+ * <li>Otherwise, prefer the {@link PackageOverride} whose version range is closest to {@code
+ * versionCode} from above.
+ * </ul>
+ */
+ private static final class PackageOverrideComparator implements Comparator<PackageOverride> {
+ private final long mVersionCode;
+
+ PackageOverrideComparator(long versionCode) {
+ this.mVersionCode = versionCode;
+ }
+
+ @Override
+ public int compare(PackageOverride o1, PackageOverride o2) {
+ // Prefer overrides whose version range contains versionCode.
+ boolean isVersionInRange1 = isVersionInRange(o1, mVersionCode);
+ boolean isVersionInRange2 = isVersionInRange(o2, mVersionCode);
+ if (isVersionInRange1 != isVersionInRange2) {
+ return isVersionInRange1 ? -1 : 1;
+ }
+
+ // Otherwise, prefer overrides whose version range is before versionCode.
+ boolean isVersionAfterRange1 = isVersionAfterRange(o1, mVersionCode);
+ boolean isVersionAfterRange2 = isVersionAfterRange(o2, mVersionCode);
+ if (isVersionAfterRange1 != isVersionAfterRange2) {
+ return isVersionAfterRange1 ? -1 : 1;
+ }
+
+ // If both overrides' version ranges are either before or after versionCode, prefer
+ // those whose version range is closer to versionCode.
+ return Long.compare(
+ getVersionProximity(o1, mVersionCode), getVersionProximity(o2, mVersionCode));
+ }
+
+ /**
+ * Returns true if the version range in the given {@code override} contains {@code
+ * versionCode}.
+ */
+ private static boolean isVersionInRange(PackageOverride override, long versionCode) {
+ return override.getMinVersionCode() <= versionCode
+ && versionCode <= override.getMaxVersionCode();
+ }
+
+ /**
+ * Returns true if the given {@code versionCode} is strictly after the version range in the
+ * given {@code override}.
+ */
+ private static boolean isVersionAfterRange(PackageOverride override, long versionCode) {
+ return override.getMaxVersionCode() < versionCode;
+ }
+
+ /**
+ * Returns true if the given {@code versionCode} is strictly before the version range in the
+ * given {@code override}.
+ */
+ private static boolean isVersionBeforeRange(PackageOverride override, long versionCode) {
+ return override.getMinVersionCode() > versionCode;
+ }
+
+ /**
+ * In case the given {@code versionCode} is strictly before or after the version range in
+ * the given {@code override}, returns the distance from it, otherwise returns zero.
+ */
+ private static long getVersionProximity(PackageOverride override, long versionCode) {
+ if (isVersionAfterRange(override, versionCode)) {
+ return versionCode - override.getMaxVersionCode();
+ }
+ if (isVersionBeforeRange(override, versionCode)) {
+ return override.getMinVersionCode() - versionCode;
+ }
+
+ // Version is in range. Note that when two overrides have a zero version proximity
+ // they will be ordered arbitrarily.
+ return 0;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
new file mode 100644
index 0000000..63ae1af
--- /dev/null
+++ b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
@@ -0,0 +1,408 @@
+/*
+ * 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.compat.overrides;
+
+import static android.content.Intent.ACTION_PACKAGE_ADDED;
+import static android.content.Intent.ACTION_PACKAGE_CHANGED;
+import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.provider.DeviceConfig.NAMESPACE_APP_COMPAT_OVERRIDES;
+
+import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_OWNED_CHANGE_IDS;
+import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_REMOVE_OVERRIDES;
+
+import static java.util.Collections.emptySet;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.compat.PackageOverride;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
+import com.android.internal.compat.IPlatformCompat;
+import com.android.server.SystemService;
+import com.android.server.compat.overrides.AppCompatOverridesParser.PackageOverrides;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Service for applying per-app compat overrides delivered via Device Config.
+ *
+ * <p>The service listens both on changes to supported Device Config namespaces and on package
+ * added/changed/removed events, and applies overrides accordingly.
+ *
+ * @hide
+ */
+public final class AppCompatOverridesService {
+ private static final String TAG = "AppCompatOverridesService";
+
+ private static final List<String> SUPPORTED_NAMESPACES = Arrays.asList(
+ NAMESPACE_APP_COMPAT_OVERRIDES);
+
+ private final Context mContext;
+ private final PackageManager mPackageManager;
+ private final IPlatformCompat mPlatformCompat;
+ private final List<String> mSupportedNamespaces;
+ private final AppCompatOverridesParser mOverridesParser;
+ private final PackageReceiver mPackageReceiver;
+ private final List<DeviceConfigListener> mDeviceConfigListeners;
+
+ private AppCompatOverridesService(Context context) {
+ this(context, IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)), SUPPORTED_NAMESPACES);
+ }
+
+ @VisibleForTesting
+ AppCompatOverridesService(Context context, IPlatformCompat platformCompat,
+ List<String> supportedNamespaces) {
+ mContext = context;
+ mPackageManager = mContext.getPackageManager();
+ mPlatformCompat = platformCompat;
+ mSupportedNamespaces = supportedNamespaces;
+ mOverridesParser = new AppCompatOverridesParser(mPackageManager);
+ mPackageReceiver = new PackageReceiver(mContext);
+ mDeviceConfigListeners = new ArrayList<>();
+ for (String namespace : mSupportedNamespaces) {
+ mDeviceConfigListeners.add(new DeviceConfigListener(mContext, namespace));
+ }
+ }
+
+ @Override
+ public void finalize() {
+ unregisterDeviceConfigListeners();
+ unregisterPackageReceiver();
+ }
+
+ @VisibleForTesting
+ void registerDeviceConfigListeners() {
+ for (DeviceConfigListener listener : mDeviceConfigListeners) {
+ listener.register();
+ }
+ }
+
+ private void unregisterDeviceConfigListeners() {
+ for (DeviceConfigListener listener : mDeviceConfigListeners) {
+ listener.unregister();
+ }
+ }
+
+ @VisibleForTesting
+ void registerPackageReceiver() {
+ mPackageReceiver.register();
+ }
+
+ private void unregisterPackageReceiver() {
+ mPackageReceiver.unregister();
+ }
+
+ /**
+ * Same as {@link #applyOverrides(Properties, Map)} except all properties of the given {@code
+ * namespace} are fetched via {@link DeviceConfig#getProperties}.
+ */
+ private void applyAllOverrides(String namespace,
+ Map<String, Set<Long>> packageToChangeIdsToSkip) {
+ applyOverrides(DeviceConfig.getProperties(namespace), packageToChangeIdsToSkip);
+ }
+
+ /**
+ * Iterates all package override flags in the given {@code properties}, and for each flag whose
+ * package is installed on the device, parses its value and applies the overrides in it with
+ * respect to the package's current installed version.
+ */
+ private void applyOverrides(Properties properties,
+ Map<String, Set<Long>> packageToChangeIdsToSkip) {
+ Set<String> packageNames = new ArraySet<>(properties.getKeyset());
+ packageNames.remove(FLAG_OWNED_CHANGE_IDS);
+ packageNames.remove(FLAG_REMOVE_OVERRIDES);
+ for (String packageName : packageNames) {
+ Long versionCode = getVersionCodeOrNull(packageName);
+ if (versionCode == null) {
+ // Package isn't installed yet.
+ continue;
+ }
+
+ applyPackageOverrides(properties.getString(packageName, /* defaultValue= */ ""),
+ packageName, versionCode,
+ packageToChangeIdsToSkip.getOrDefault(packageName, emptySet()));
+ }
+ }
+
+ /**
+ * Applies all overrides in all supported namespaces for the given {@code packageName}.
+ */
+ private void applyAllPackageOverrides(String packageName) {
+ Long versionCode = getVersionCodeOrNull(packageName);
+ if (versionCode == null) {
+ return;
+ }
+
+ for (String namespace : mSupportedNamespaces) {
+ // We apply overrides for each namespace separately so that if there is a failure for
+ // one namespace, the other namespaces won't be affected.
+ applyPackageOverrides(
+ DeviceConfig.getString(namespace, packageName, /* defaultValue= */ ""),
+ packageName, versionCode,
+ getOverridesToRemove(namespace).getOrDefault(packageName, emptySet()));
+ }
+ }
+
+ /**
+ * Calls {@link AppCompatOverridesParser#parsePackageOverrides} on the given arguments, adds the
+ * resulting {@link PackageOverrides#overridesToAdd} via {@link
+ * IPlatformCompat#putOverridesOnReleaseBuilds}, and removes the resulting {@link
+ * PackageOverrides#overridesToRemove} via {@link
+ * IPlatformCompat#removeOverridesOnReleaseBuilds}.
+ */
+ private void applyPackageOverrides(String configStr, String packageName,
+ long versionCode, Set<Long> changeIdsToSkip) {
+ PackageOverrides packageOverrides = AppCompatOverridesParser.parsePackageOverrides(
+ configStr, versionCode, changeIdsToSkip);
+ putPackageOverrides(packageName, packageOverrides.overridesToAdd);
+ removePackageOverrides(packageName, packageOverrides.overridesToRemove);
+ }
+
+ /**
+ * Removes all owned overrides in all supported namespaces for the given {@code packageName}.
+ *
+ * <p>If a certain namespace doesn't have a package override flag for the given {@code
+ * packageName}, that namespace is skipped.</p>
+ */
+ private void removeAllPackageOverrides(String packageName) {
+ for (String namespace : mSupportedNamespaces) {
+ if (DeviceConfig.getString(namespace, packageName, /* defaultValue= */ "").isEmpty()) {
+ // No overrides for this package in this namespace.
+ continue;
+ }
+ // We remove overrides for each namespace separately so that if there is a failure for
+ // one namespace, the other namespaces won't be affected.
+ removePackageOverrides(packageName, getOwnedChangeIds(namespace));
+ }
+ }
+
+ /**
+ * Calls {@link IPlatformCompat#removeOverridesOnReleaseBuilds} on each package name and
+ * respective change IDs in {@code overridesToRemove}.
+ */
+ private void removeOverrides(Map<String, Set<Long>> overridesToRemove) {
+ for (Map.Entry<String, Set<Long>> packageNameAndOverrides : overridesToRemove.entrySet()) {
+ removePackageOverrides(packageNameAndOverrides.getKey(),
+ packageNameAndOverrides.getValue());
+ }
+ }
+
+ /**
+ * Fetches the value of {@link AppCompatOverridesParser#FLAG_REMOVE_OVERRIDES} for the given
+ * {@code namespace} and parses it into a map from package name to a set of change IDs to
+ * remove for that package.
+ */
+ private Map<String, Set<Long>> getOverridesToRemove(String namespace) {
+ return mOverridesParser.parseRemoveOverrides(
+ DeviceConfig.getString(namespace, FLAG_REMOVE_OVERRIDES, /* defaultValue= */ ""),
+ getOwnedChangeIds(namespace));
+ }
+
+ /**
+ * Fetches the value of {@link AppCompatOverridesParser#FLAG_OWNED_CHANGE_IDS} for the given
+ * {@code namespace} and parses it into a set of change IDs.
+ */
+ private static Set<Long> getOwnedChangeIds(String namespace) {
+ return AppCompatOverridesParser.parseOwnedChangeIds(
+ DeviceConfig.getString(namespace, FLAG_OWNED_CHANGE_IDS, /* defaultValue= */ ""));
+ }
+
+ private void putPackageOverrides(String packageName,
+ Map<Long, PackageOverride> overridesToAdd) {
+ if (overridesToAdd.isEmpty()) {
+ return;
+ }
+ CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(overridesToAdd);
+ try {
+ mPlatformCompat.putOverridesOnReleaseBuilds(config, packageName);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to call IPlatformCompat#putOverridesOnReleaseBuilds", e);
+ }
+ }
+
+ private void removePackageOverrides(String packageName, Set<Long> overridesToRemove) {
+ if (overridesToRemove.isEmpty()) {
+ return;
+ }
+ CompatibilityOverridesToRemoveConfig config = new CompatibilityOverridesToRemoveConfig(
+ overridesToRemove);
+ try {
+ mPlatformCompat.removeOverridesOnReleaseBuilds(config, packageName);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to call IPlatformCompat#removeOverridesOnReleaseBuilds", e);
+ }
+ }
+
+ private boolean isInstalledForAnyUser(String packageName) {
+ return getVersionCodeOrNull(packageName) != null;
+ }
+
+ @Nullable
+ private Long getVersionCodeOrNull(String packageName) {
+ try {
+ ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(packageName,
+ MATCH_ANY_USER);
+ return applicationInfo.longVersionCode;
+ } catch (PackageManager.NameNotFoundException e) {
+ // Package isn't installed for any user.
+ return null;
+ }
+ }
+
+ /**
+ * SystemService lifecycle for AppCompatOverridesService.
+ *
+ * @hide
+ */
+ public static final class Lifecycle extends SystemService {
+ private AppCompatOverridesService mService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mService = new AppCompatOverridesService(getContext());
+ mService.registerDeviceConfigListeners();
+ mService.registerPackageReceiver();
+ }
+ }
+
+ /**
+ * A {@link DeviceConfig.OnPropertiesChangedListener} that listens on changes to a given
+ * namespace and adds/removes overrides according to the changed flags.
+ */
+ private final class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener {
+ private final Context mContext;
+ private final String mNamespace;
+
+ private DeviceConfigListener(Context context, String namespace) {
+ mContext = context;
+ mNamespace = namespace;
+ }
+
+ private void register() {
+ DeviceConfig.addOnPropertiesChangedListener(mNamespace, mContext.getMainExecutor(),
+ this);
+ }
+
+ private void unregister() {
+ DeviceConfig.removeOnPropertiesChangedListener(this);
+ }
+
+ @Override
+ public void onPropertiesChanged(Properties properties) {
+ boolean removeOverridesFlagChanged = properties.getKeyset().contains(
+ FLAG_REMOVE_OVERRIDES);
+ boolean ownedChangedIdsFlagChanged = properties.getKeyset().contains(
+ FLAG_OWNED_CHANGE_IDS);
+
+ Map<String, Set<Long>> overridesToRemove = getOverridesToRemove(mNamespace);
+ if (removeOverridesFlagChanged || ownedChangedIdsFlagChanged) {
+ // In both cases it's possible that overrides that weren't removed before should
+ // now be removed.
+ removeOverrides(overridesToRemove);
+ }
+
+ if (removeOverridesFlagChanged) {
+ // We need to re-apply all overrides in the namespace since the remove overrides
+ // flag might have blocked some of them from being applied before.
+ applyAllOverrides(mNamespace, overridesToRemove);
+ } else {
+ applyOverrides(properties, overridesToRemove);
+ }
+ }
+ }
+
+ /**
+ * A {@link BroadcastReceiver} that listens on package added/changed/removed events and
+ * adds/removes overrides according to the corresponding Device Config flags.
+ */
+ private final class PackageReceiver extends BroadcastReceiver {
+ private final Context mContext;
+ private final IntentFilter mIntentFilter;
+
+ private PackageReceiver(Context context) {
+ mContext = context;
+ mIntentFilter = new IntentFilter();
+ mIntentFilter.addAction(ACTION_PACKAGE_ADDED);
+ mIntentFilter.addAction(ACTION_PACKAGE_CHANGED);
+ mIntentFilter.addAction(ACTION_PACKAGE_REMOVED);
+ mIntentFilter.addDataScheme("package");
+ }
+
+ private void register() {
+ mContext.registerReceiverForAllUsers(this, mIntentFilter, /* broadcastPermission= */
+ null, /* scheduler= */ null);
+ }
+
+ private void unregister() {
+ mContext.unregisterReceiver(this);
+ }
+
+ @Override
+ public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
+ Uri data = intent.getData();
+ if (data == null) {
+ Slog.w(TAG, "Failed to get package name in package receiver");
+ return;
+ }
+ String packageName = data.getSchemeSpecificPart();
+ String action = intent.getAction();
+ if (action == null) {
+ Slog.w(TAG, "Failed to get action in package receiver");
+ return;
+ }
+ switch (action) {
+ case ACTION_PACKAGE_ADDED:
+ case ACTION_PACKAGE_CHANGED:
+ applyAllPackageOverrides(packageName);
+ break;
+ case ACTION_PACKAGE_REMOVED:
+ if (!isInstalledForAnyUser(packageName)) {
+ removeAllPackageOverrides(packageName);
+ }
+ break;
+ default:
+ Slog.w(TAG, "Unsupported action in package receiver: " + action);
+ break;
+ }
+ }
+ };
+}
diff --git a/services/core/java/com/android/server/compat/overrides/TEST_MAPPING b/services/core/java/com/android/server/compat/overrides/TEST_MAPPING
new file mode 100644
index 0000000..4b8f08e
--- /dev/null
+++ b/services/core/java/com/android/server/compat/overrides/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksMockingServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.compat.overrides"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index fb919fb..53c13c7 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -28,7 +28,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.Notification;
import android.app.NotificationManager;
@@ -323,6 +323,8 @@
private final PackageManagerInternal mPackageManagerInternal;
+ private final ActivityManagerInternal mAmi;
+
private List<UserInfo> getAllUsers() {
return mUserManager.getUsers();
}
@@ -643,6 +645,7 @@
mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+ mAmi = LocalServices.getService(ActivityManagerInternal.class);
mAccountManagerInternal.addOnAppPermissionChangeListener((Account account, int uid) -> {
// If the UID gained access to the account kick-off syncs lacking account access
@@ -1115,15 +1118,11 @@
}
final int owningUid = syncAdapterInfo.uid;
final String owningPackage = syncAdapterInfo.componentName.getPackageName();
- try {
- if (ActivityManager.getService().isAppStartModeDisabled(owningUid, owningPackage)) {
- Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
- + syncAdapterInfo.componentName
- + " -- package not allowed to start");
- return AuthorityInfo.NOT_SYNCABLE;
- }
- } catch (RemoteException e) {
- /* ignore - local call */
+ if (mAmi.isAppStartModeDisabled(owningUid, owningPackage)) {
+ Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
+ + syncAdapterInfo.componentName
+ + " -- package not allowed to start");
+ return AuthorityInfo.NOT_SYNCABLE;
}
if (checkAccountAccess && !canAccessAccount(account, owningPackage, owningUid)) {
Log.w(TAG, "Access to " + logSafe(account) + " denied for package "
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 7955ecac..de78bec 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -44,7 +44,6 @@
import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_IME_WITH_HARD_KEYBOARD;
import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_REQUESTED;
import static android.server.inputmethod.InputMethodManagerServiceProto.SYSTEM_READY;
-import static android.util.imetracing.ImeTracing.IME_TRACING_FROM_IMMS;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_HIDE;
@@ -124,7 +123,6 @@
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
-import android.util.imetracing.ImeTracing;
import android.util.proto.ProtoOutputStream;
import android.view.IWindowManager;
import android.view.InputChannel;
@@ -160,6 +158,7 @@
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.IVoidResultCallback;
+import com.android.internal.inputmethod.ImeTracing;
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.inputmethod.StartInputFlags;
@@ -3927,7 +3926,7 @@
@BinderThread
@Override
public void startProtoDump(byte[] protoDump, int source, String where) {
- if (protoDump == null && source != IME_TRACING_FROM_IMMS) {
+ if (protoDump == null && source != ImeTracing.IME_TRACING_FROM_IMMS) {
// Dump not triggered from IMMS, but no proto information provided.
return;
}
@@ -3954,7 +3953,7 @@
proto.write(InputMethodServiceTraceProto.INPUT_METHOD_SERVICE, protoDump);
proto.end(service_token);
break;
- case IME_TRACING_FROM_IMMS:
+ case ImeTracing.IME_TRACING_FROM_IMMS:
final long managerservice_token =
proto.start(InputMethodManagerServiceTraceFileProto.ENTRY);
proto.write(InputMethodManagerServiceTraceProto.ELAPSED_REALTIME_NANOS,
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 5c1ce64..8c9068d 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -155,7 +155,7 @@
private static final float FASTEST_INTERVAL_JITTER_PERCENTAGE = .10f;
// max absolute jitter allowed for min update interval evaluation
- private static final int MAX_FASTEST_INTERVAL_JITTER_MS = 5 * 1000;
+ private static final int MAX_FASTEST_INTERVAL_JITTER_MS = 30 * 1000;
// minimum amount of request delay in order to respect the delay, below this value the request
// will just be scheduled immediately
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index b144ff2..16a0b7e 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -372,7 +372,7 @@
}
}
if (rule.enabled != automaticZenRule.isEnabled()) {
- dispatchOnAutomaticRuleStatusChanged(mConfig.user, rule.pkg, ruleId,
+ dispatchOnAutomaticRuleStatusChanged(mConfig.user, rule.getPkg(), ruleId,
automaticZenRule.isEnabled()
? AUTOMATIC_RULE_STATUS_ENABLED : AUTOMATIC_RULE_STATUS_DISABLED);
}
@@ -391,13 +391,14 @@
if (ruleToRemove == null) return false;
if (canManageAutomaticZenRule(ruleToRemove)) {
newConfig.automaticRules.remove(id);
- if (ruleToRemove.pkg != null && !"android".equals(ruleToRemove.pkg)) {
+ if (ruleToRemove.getPkg() != null && !"android".equals(ruleToRemove.getPkg())) {
for (ZenRule currRule : newConfig.automaticRules.values()) {
- if (currRule.pkg != null && currRule.pkg.equals(ruleToRemove.pkg)) {
+ if (currRule.getPkg() != null
+ && currRule.getPkg().equals(ruleToRemove.getPkg())) {
break; // no need to remove from cache
}
}
- mRulesUidCache.remove(getPackageUserKey(ruleToRemove.pkg, newConfig.user));
+ mRulesUidCache.remove(getPackageUserKey(ruleToRemove.getPkg(), newConfig.user));
}
if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + id + " reason=" + reason);
} else {
@@ -405,7 +406,7 @@
"Cannot delete rules not owned by your condition provider");
}
dispatchOnAutomaticRuleStatusChanged(
- mConfig.user, ruleToRemove.pkg, id, AUTOMATIC_RULE_STATUS_REMOVED);
+ mConfig.user, ruleToRemove.getPkg(), id, AUTOMATIC_RULE_STATUS_REMOVED);
return setConfigLocked(newConfig, reason, null, true);
}
}
@@ -417,14 +418,7 @@
newConfig = mConfig.copy();
for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
- String pkg = rule.pkg != null
- ? rule.pkg
- : (rule.component != null)
- ? rule.component.getPackageName()
- : (rule.configurationActivity != null)
- ? rule.configurationActivity.getPackageName()
- : null;
- if (Objects.equals(pkg, packageName) && canManageAutomaticZenRule(rule)) {
+ if (Objects.equals(rule.getPkg(), packageName) && canManageAutomaticZenRule(rule)) {
newConfig.automaticRules.removeAt(i);
}
}
@@ -524,7 +518,7 @@
if (packages != null) {
final int packageCount = packages.length;
for (int i = 0; i < packageCount; i++) {
- if (packages[i].equals(rule.pkg)) {
+ if (packages[i].equals(rule.getPkg())) {
return true;
}
}
@@ -834,8 +828,8 @@
ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
try {
- if (rule.pkg != null) {
- mPm.getPackageInfo(rule.pkg, PackageManager.MATCH_ANY_USER);
+ if (rule.getPkg() != null) {
+ mPm.getPackageInfo(rule.getPkg(), PackageManager.MATCH_ANY_USER);
}
} catch (PackageManager.NameNotFoundException e) {
newConfig.automaticRules.removeAt(i);
@@ -1246,7 +1240,7 @@
}
// Look for packages and enablers, enablers get priority.
- String pkg = rule.pkg == null ? "" : rule.pkg;
+ String pkg = rule.getPkg() == null ? "" : rule.getPkg();
if (rule.enabler != null) {
pkg = rule.enabler;
id = ZenModeConfig.MANUAL_RULE_ID;
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index fbea438..c0a378a6 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -1051,13 +1051,18 @@
final ParsedPackage parsedPackage2 = packageParser.parsePackage(
new File(apexInfo.modulePath), flags, /* useCaches= */ false);
final PackageInfo finalApexPkg = PackageInfoWithoutStateUtils.generate(
- parsedPackage, apexInfo, flags);
+ parsedPackage2, apexInfo, flags);
// Installation was successful, time to update mAllPackagesCache
synchronized (mLock) {
- for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
- if (mAllPackagesCache.get(i).equals(existingApexPkg)) {
- mAllPackagesCache.set(i, finalApexPkg);
- break;
+ if (isFactory(existingApexPkg)) {
+ existingApexPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
+ mAllPackagesCache.add(finalApexPkg);
+ } else {
+ for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
+ if (mAllPackagesCache.get(i).equals(existingApexPkg)) {
+ mAllPackagesCache.set(i, finalApexPkg);
+ break;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f299845..4a1e356 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -112,8 +112,6 @@
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
-import static com.android.internal.util.ArrayUtils.emptyIfNull;
-import static com.android.internal.util.ArrayUtils.filter;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
@@ -17379,6 +17377,7 @@
} catch (PackageManagerException e) {
request.installResult.setError("APEX installation failed", e);
}
+ invalidatePackageInfoCache();
notifyInstallObserver(request.installResult, request.args.observer);
}
@@ -23624,18 +23623,6 @@
getPackageFromComponentString(R.string.config_defaultAppPredictionService));
}
- private @NonNull String[] dropNonSystemPackages(@NonNull String[] pkgNames) {
- return emptyIfNull(filter(pkgNames, String[]::new, mIsSystemPackage), String.class);
- }
-
- private Predicate<String> mIsSystemPackage = (pkgName) -> {
- if ("android".equals(pkgName)) {
- return true;
- }
- AndroidPackage pkg = mPackages.get(pkgName);
- return pkg != null && pkg.isSystem();
- };
-
@Override
public String getSystemCaptionsServicePackageName() {
return ensureSystemPackageName(
@@ -27285,7 +27272,7 @@
@Override
public @NonNull String[] getKnownPackageNames(int knownPackage, int userId) {
- return dropNonSystemPackages(getKnownPackageNamesInternal(knownPackage, userId));
+ return getKnownPackageNamesInternal(knownPackage, userId);
}
private String[] getKnownPackageNamesInternal(int knownPackage, int userId) {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 81ea465..3763262 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -31,6 +31,7 @@
import com.android.server.pm.permission.LegacyPermissionDataProvider;
import com.android.server.pm.permission.LegacyPermissionState;
import com.android.server.pm.pkg.PackageStateUnserialized;
+import com.android.server.utils.SnapshotCache;
import java.io.File;
import java.util.ArrayList;
@@ -81,6 +82,7 @@
* object equality to check whether shared user settings are the same.
*/
SharedUserSetting sharedUser;
+
/**
* Temporary holding space for the shared user ID. While parsing package settings, the
* shared users tag may come after the packages. In this case, we must delay linking the
@@ -103,6 +105,19 @@
@NonNull
private UUID mDomainSetId;
+ /**
+ * Snapshot support.
+ */
+ private final SnapshotCache<PackageSetting> mSnapshot;
+
+ private SnapshotCache<PackageSetting> makeCache() {
+ return new SnapshotCache<PackageSetting>(this, this) {
+ @Override
+ public PackageSetting createSnapshot() {
+ return new PackageSetting(mSource, true);
+ }};
+ }
+
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public PackageSetting(String name, String realName, @NonNull File codePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
@@ -118,6 +133,7 @@
this.sharedUserId = sharedUserId;
mDomainSetId = domainSetId;
copyMimeGroups(mimeGroups);
+ mSnapshot = makeCache();
}
/**
@@ -127,6 +143,7 @@
PackageSetting(PackageSetting orig) {
super(orig, orig.realName);
doCopy(orig);
+ mSnapshot = makeCache();
}
/**
@@ -137,6 +154,33 @@
PackageSetting(PackageSetting orig, String realPkgName) {
super(orig, realPkgName);
doCopy(orig);
+ mSnapshot = makeCache();
+ }
+
+ /**
+ * Create a snapshot. The copy constructor is already in use and cannot be modified
+ * for this purpose.
+ */
+ PackageSetting(PackageSetting orig, boolean snapshot) {
+ super(orig, snapshot);
+ // The existing doCopy() method cannot be used in here because sharedUser must be
+ // a snapshot, and not a reference. Also, the pkgState must be copied. However,
+ // this code should otherwise be kept in sync with doCopy().
+ appId = orig.appId;
+ pkg = orig.pkg;
+ sharedUser = orig.sharedUser == null ? null : orig.sharedUser.snapshot();
+ sharedUserId = orig.sharedUserId;
+ copyMimeGroups(orig.mimeGroups);
+ pkgState = orig.pkgState;
+ mDomainSetId = orig.getDomainSetId();
+ mSnapshot = new SnapshotCache.Sealed();
+ }
+
+ /**
+ * Return the package snapshot.
+ */
+ public PackageSetting snapshot() {
+ return mSnapshot.snapshot();
}
/** @see #pkg **/
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index e2443c1..3d1a841 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -169,6 +169,15 @@
doCopy(base);
}
+ // A copy constructor used to create snapshots. The boolean is present only to
+ // match up with the constructor in PackageSetting.
+ PackageSettingBase(PackageSettingBase orig, boolean snapshot) {
+ super(orig);
+ name = orig.name;
+ realName = orig.realName;
+ doCopy(orig);
+ }
+
public void setInstallerPackageName(String packageName) {
installSource = installSource.setInstallerPackage(packageName);
onChanged();
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index 0e8a278..7b5c7e3 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -22,12 +22,13 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.permission.LegacyPermissionState;
+import com.android.server.utils.Snappable;
import com.android.server.utils.Watchable;
import com.android.server.utils.WatchableImpl;
import com.android.server.utils.Watcher;
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public abstract class SettingBase implements Watchable {
+public abstract class SettingBase implements Watchable, Snappable {
// TODO: make this variable protected, or even private with a getter and setter.
// Simply making it protected or private requires that the name be changed to conformm
// to the Android naming convention, and that touches quite a few files.
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 9b1c08d..8ddbe08 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -26,6 +26,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.utils.SnapshotCache;
import libcore.util.EmptyArray;
@@ -49,12 +50,25 @@
// that all apps within the sharedUser run in the same selinux context.
int seInfoTargetSdkVersion;
- final ArraySet<PackageSetting> packages = new ArraySet<>();
+ final ArraySet<PackageSetting> packages;
final PackageSignatures signatures = new PackageSignatures();
Boolean signaturesChanged;
- ArrayMap<String, ParsedProcess> processes;
+ final ArrayMap<String, ParsedProcess> processes;
+
+ /**
+ * Snapshot support.
+ */
+ private final SnapshotCache<SharedUserSetting> mSnapshot;
+
+ private SnapshotCache<SharedUserSetting> makeCache() {
+ return new SnapshotCache<SharedUserSetting>(this, this) {
+ @Override
+ public SharedUserSetting createSnapshot() {
+ return new SharedUserSetting(mSource);
+ }};
+ }
SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) {
super(_pkgFlags, _pkgPrivateFlags);
@@ -62,6 +76,31 @@
uidPrivateFlags = _pkgPrivateFlags;
name = _name;
seInfoTargetSdkVersion = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
+ packages = new ArraySet<>();
+ processes = new ArrayMap<>();
+ mSnapshot = makeCache();
+ }
+
+ // The copy constructor is used to create a snapshot
+ private SharedUserSetting(SharedUserSetting orig) {
+ super(orig);
+ name = orig.name;
+ uidFlags = orig.uidFlags;
+ uidPrivateFlags = orig.uidPrivateFlags;
+ packages = new ArraySet(orig.packages);
+ // A PackageParser.SigningDetails seems to consist solely of final attributes, so
+ // it is safe to copy the reference.
+ signatures.mSigningDetails = orig.signatures.mSigningDetails;
+ signaturesChanged = orig.signaturesChanged;
+ processes = new ArrayMap(orig.processes);
+ mSnapshot = new SnapshotCache.Sealed();
+ }
+
+ /**
+ * Return a read-only snapshot of this object.
+ */
+ public SharedUserSetting snapshot() {
+ return mSnapshot.snapshot();
}
@Override
@@ -80,9 +119,6 @@
void addProcesses(Map<String, ParsedProcess> newProcs) {
if (newProcs != null) {
final int numProcs = newProcs.size();
- if (processes == null) {
- processes = new ArrayMap<>(numProcs);
- }
for (String key : newProcs.keySet()) {
ParsedProcess newProc = newProcs.get(key);
ParsedProcess proc = processes.get(newProc.getName());
@@ -191,7 +227,7 @@
* Update tracked data about processes based on all known packages in the shared user ID.
*/
public void updateProcesses() {
- processes = null;
+ processes.clear();
for (int i = packages.size() - 1; i >= 0; i--) {
final AndroidPackage pkg = packages.valueAt(i).pkg;
if (pkg != null) {
@@ -230,14 +266,15 @@
this.signaturesChanged = sharedUser.signaturesChanged;
if (sharedUser.processes != null) {
final int numProcs = sharedUser.processes.size();
- this.processes = new ArrayMap<>(numProcs);
+ this.processes.clear();
+ this.processes.ensureCapacity(numProcs);
for (int i = 0; i < numProcs; i++) {
ParsedProcess proc =
new ParsedProcess(sharedUser.processes.valueAt(i));
this.processes.put(proc.getName(), proc);
}
} else {
- this.processes = null;
+ this.processes.clear();
}
onChanged();
return this;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index cfdcac9..a2e4195 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2921,7 +2921,9 @@
wasChanged = true;
}
- if ((flags & FLAG_PERMISSION_REVOKED_COMPAT) != 0) {
+ if ((flags & FLAG_PERMISSION_REVOKED_COMPAT) != 0
+ && !isPermissionSplitFromNonRuntime(permName,
+ pkg.getTargetSdkVersion())) {
flags &= ~FLAG_PERMISSION_REVOKED_COMPAT;
wasChanged = true;
// Hard restricted permissions cannot be held.
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index 9026262..ab71355 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -189,12 +189,16 @@
return false;
}
- // 3. The app has WRITE_MEDIA_STORAGE, OR
- // the app already has legacy external storage or requested it,
- // and is < R.
- return hasWriteMediaStorageGrantedForUid
- || ((hasLegacyExternalStorage || hasRequestedLegacyExternalStorage)
- && targetSDK < Build.VERSION_CODES.R);
+ // 3. The app targetSDK should be less than R
+ if (targetSDK >= Build.VERSION_CODES.R) {
+ return false;
+ }
+
+ // 4. The app has WRITE_MEDIA_STORAGE,
+ // OR the app already has legacy external storage
+ // OR the app requested legacy external storage
+ return hasWriteMediaStorageGrantedForUid || hasLegacyExternalStorage
+ || hasRequestedLegacyExternalStorage;
}
@Override
public boolean mayDenyExtraAppOpIfGranted() {
@@ -216,10 +220,8 @@
return true;
}
- // The package doesn't have WRITE_MEDIA_STORAGE,
- // AND didn't request legacy storage to be preserved
- if (!hasWriteMediaStorageGrantedForUid
- && !hasRequestedPreserveLegacyExternalStorage) {
+ // The package doesn't request legacy storage to be preserved
+ if (!hasRequestedPreserveLegacyExternalStorage) {
return true;
}
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index f72adb60..1321873 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -970,6 +970,12 @@
final long token = Binder.clearCallingIdentity();
try {
CompressedApexInfoList apexInfoList = getCompressedApexInfoList(packageFile);
+ if (apexInfoList == null) {
+ Log.i(TAG, "apex_info.pb not present in OTA package. "
+ + "Assuming device doesn't support compressed"
+ + "APEX, continueing without allocating space.");
+ return true;
+ }
ApexManager apexManager = ApexManager.getInstance();
apexManager.reserveSpaceForCompressedApex(apexInfoList);
return true;
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index a436e6b..d95e826 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -22,6 +22,7 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
+import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -132,7 +133,7 @@
/** @see com.android.internal.statusbar.IStatusBar#onSystemBarAttributesChanged */
void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, boolean isFullscreen);
+ @Behavior int behavior, InsetsState requestedState, String packageName);
/** @see com.android.internal.statusbar.IStatusBar#showTransient */
void showTransient(int displayId, @InternalInsetsType int[] types);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 3a7e13b..47fdc4e 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -59,6 +59,7 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -526,13 +527,13 @@
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, boolean isFullscreen) {
+ @Behavior int behavior, InsetsState requestedState, String packageName) {
getUiState(displayId).setBarAttributes(appearance, appearanceRegions,
- navbarColorManagedByIme, behavior, isFullscreen);
+ navbarColorManagedByIme, behavior, requestedState, packageName);
if (mBar != null) {
try {
mBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
- navbarColorManagedByIme, behavior, isFullscreen);
+ navbarColorManagedByIme, behavior, requestedState, packageName);
} catch (RemoteException ex) { }
}
}
@@ -1103,13 +1104,14 @@
return state;
}
- private class UiState {
+ private static class UiState {
private @Appearance int mAppearance = 0;
private AppearanceRegion[] mAppearanceRegions = new AppearanceRegion[0];
- private ArraySet<Integer> mTransientBarTypes = new ArraySet<>();
+ private final ArraySet<Integer> mTransientBarTypes = new ArraySet<>();
private boolean mNavbarColorManagedByIme = false;
private @Behavior int mBehavior;
- private boolean mFullscreen = false;
+ private InsetsState mRequestedState = new InsetsState();
+ private String mPackageName = "none";
private int mDisabled1 = 0;
private int mDisabled2 = 0;
private int mImeWindowVis = 0;
@@ -1119,12 +1121,13 @@
private void setBarAttributes(@Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, boolean isFullscreen) {
+ @Behavior int behavior, InsetsState requestedState, String packageName) {
mAppearance = appearance;
mAppearanceRegions = appearanceRegions;
mNavbarColorManagedByIme = navbarColorManagedByIme;
mBehavior = behavior;
- mFullscreen = isFullscreen;
+ mRequestedState = requestedState;
+ mPackageName = packageName;
}
private void showTransient(@InternalInsetsType int[] types) {
@@ -1244,8 +1247,8 @@
state.mAppearance, state.mAppearanceRegions, state.mImeWindowVis,
state.mImeBackDisposition, state.mShowImeSwitcher,
gatherDisableActionsLocked(mCurrentUserId, 2), state.mImeToken,
- state.mNavbarColorManagedByIme, state.mBehavior, state.mFullscreen,
- transientBarTypes);
+ state.mNavbarColorManagedByIme, state.mBehavior, state.mRequestedState,
+ state.mPackageName, transientBarTypes);
}
}
diff --git a/services/core/java/com/android/server/timedetector/TEST_MAPPING b/services/core/java/com/android/server/timedetector/TEST_MAPPING
new file mode 100644
index 0000000..f1bfea7
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/TEST_MAPPING
@@ -0,0 +1,20 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.timedetector."
+ }
+ ]
+ },
+ {
+ "name": "CtsTimeTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TEST_MAPPING b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
index 91e172c..b1ae626 100644
--- a/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
+++ b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
@@ -7,6 +7,14 @@
"include-filter": "com.android.server.timezonedetector."
}
]
+ },
+ {
+ "name": "CtsTimeTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
]
}
diff --git a/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java b/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
index d2190fd..b1019f3 100644
--- a/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
@@ -166,12 +166,6 @@
stopProviders();
mPrimaryProvider.destroy();
mSecondaryProvider.destroy();
-
- // If the controller has made a "certain" suggestion, it should make an uncertain
- // suggestion to cancel it.
- if (mLastSuggestion != null && mLastSuggestion.getZoneIds() != null) {
- makeSuggestion(createUncertainSuggestion("Controller is destroyed"));
- }
}
}
@@ -182,6 +176,16 @@
// By definition, if both providers are stopped, the controller is uncertain.
cancelUncertaintyTimeout();
+
+ // If a previous "certain" suggestion has been made, then a new "uncertain"
+ // suggestion must now be made to indicate the controller {does not / no longer has}
+ // an opinion and will not be sending further updates (until at least the providers are
+ // re-started).
+ if (mLastSuggestion != null && mLastSuggestion.getZoneIds() != null) {
+ GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
+ "Providers are stopping");
+ makeSuggestion(suggestion);
+ }
}
@GuardedBy("mSharedLock")
@@ -275,21 +279,6 @@
}
} else {
stopProviders();
-
- // There can be an uncertainty timeout set if the controller most recently received
- // an uncertain event. This is a no-op if there isn't a timeout set.
- cancelUncertaintyTimeout();
-
- // If a previous "certain" suggestion has been made, then a new "uncertain"
- // suggestion must now be made to indicate the controller {does not / no longer has}
- // an opinion and will not be sending further updates (until at least the config
- // changes again and providers are re-started).
- if (mLastSuggestion != null && mLastSuggestion.getZoneIds() != null) {
- GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
- "Provider is stopped:"
- + " primary=" + mPrimaryProvider.getCurrentState());
- makeSuggestion(suggestion);
- }
}
}
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index 0386372..dd4e260 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -1294,21 +1294,32 @@
@Override
public boolean shouldPlayWhenVibratorComplete(int vibratorId) {
if (controller.getVibratorInfo().getId() == vibratorId) {
+ mVibratorCallbackReceived = true;
mNextOffTime = SystemClock.uptimeMillis();
}
- // Timings are tightly controlled here, so never anticipate when vibrator is complete.
- return false;
+ // Timings are tightly controlled here, so only anticipate if the vibrator was supposed
+ // to be ON but has completed prematurely, to turn it back on as soon as possible.
+ return mNextOffTime < startTime && controller.getCurrentAmplitude() > 0;
}
@Override
public List<Step> play() {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "AmplitudeStep");
try {
+ long now = SystemClock.uptimeMillis();
+ long latency = now - startTime;
if (DEBUG) {
- long latency = SystemClock.uptimeMillis() - startTime;
Slog.d(TAG, "Running amplitude step with " + latency + "ms latency.");
}
+ if (mVibratorCallbackReceived && latency < 0) {
+ // This step was anticipated because the vibrator turned off prematurely.
+ // Turn it back on and return this same step to run at the exact right time.
+ mNextOffTime = turnVibratorBackOn(/* remainingDuration= */ -latency);
+ return Arrays.asList(new AmplitudeStep(startTime, controller, effect,
+ segmentIndex, mNextOffTime));
+ }
+
VibrationEffectSegment segment = effect.getSegments().get(segmentIndex);
if (!(segment instanceof StepSegment)) {
Slog.w(TAG, "Ignoring wrong segment for a AmplitudeStep: " + segment);
@@ -1321,17 +1332,16 @@
return skipToNextSteps(/* segmentsSkipped= */ 1);
}
- long now = SystemClock.uptimeMillis();
float amplitude = stepSegment.getAmplitude();
if (amplitude == 0) {
- if (mNextOffTime > now) {
+ if (vibratorOffTimeout > now) {
// Amplitude cannot be set to zero, so stop the vibrator.
stopVibrating();
mNextOffTime = now;
}
} else {
if (startTime >= mNextOffTime) {
- // Vibrator has stopped. Turn vibrator back on for the duration of another
+ // Vibrator is OFF. Turn vibrator back on for the duration of another
// cycle before setting the amplitude.
long onDuration = getVibratorOnDuration(effect, segmentIndex);
if (onDuration > 0) {
@@ -1350,6 +1360,22 @@
}
}
+ private long turnVibratorBackOn(long remainingDuration) {
+ long onDuration = getVibratorOnDuration(effect, segmentIndex);
+ if (onDuration <= 0) {
+ // Vibrator is supposed to go back off when this step starts, so just leave it off.
+ return vibratorOffTimeout;
+ }
+ onDuration += remainingDuration;
+ float expectedAmplitude = controller.getCurrentAmplitude();
+ mVibratorOnResult = startVibrating(onDuration);
+ if (mVibratorOnResult > 0) {
+ // Set the amplitude back to the value it was supposed to be playing at.
+ changeAmplitude(expectedAmplitude);
+ }
+ return SystemClock.uptimeMillis() + onDuration + CALLBACKS_EXTRA_TIMEOUT;
+ }
+
private long startVibrating(long duration) {
if (DEBUG) {
Slog.d(TAG, "Turning on vibrator " + controller.getVibratorInfo().getId() + " for "
@@ -1383,7 +1409,10 @@
repeatIndex = -1;
}
if (i == startIndex) {
- return 1000;
+ // The repeating waveform keeps the vibrator ON all the time. Use a minimum
+ // of 1s duration to prevent short patterns from turning the vibrator ON too
+ // frequently.
+ return Math.max(timing, 1000);
}
}
if (i == segmentCount && effect.getRepeatIndex() < 0) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c2c41ff..707b369 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -830,6 +830,10 @@
// Tracking cookie for the launch of this activity and it's task.
IBinder mLaunchCookie;
+ // Entering PiP is usually done in two phases, we put the task into pinned mode first and
+ // SystemUi sets the pinned mode on activity after transition is done.
+ boolean mWaitForEnteringPinnedMode;
+
private final Runnable mPauseTimeoutRunnable = new Runnable() {
@Override
public void run() {
@@ -5277,7 +5281,8 @@
// returns. Just need to confirm this reasoning makes sense.
final boolean deferHidingClient = canEnterPictureInPicture
&& !isState(STARTED, STOPPING, STOPPED, PAUSED);
- if (deferHidingClient && pictureInPictureArgs.isAutoEnterEnabled()) {
+ if (!mAtmService.getTransitionController().isShellTransitionsEnabled()
+ && deferHidingClient && pictureInPictureArgs.isAutoEnterEnabled()) {
// Go ahead and just put the activity in pip if it supports auto-pip.
mAtmService.enterPictureInPictureMode(this, pictureInPictureArgs);
return;
@@ -7896,6 +7901,7 @@
// 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) {
+ mWaitForEnteringPinnedMode = false;
mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, task.getBounds());
}
@@ -8185,7 +8191,9 @@
if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) {
// Aha, the activity isn't handling the change, so DIE DIE DIE.
configChangeFlags |= changes;
- startFreezingScreenLocked(globalChanges);
+ if (!mAtmService.getTransitionController().isShellTransitionsEnabled()) {
+ startFreezingScreenLocked(globalChanges);
+ }
forceNewConfig = false;
preserveWindow &= isResizeOnlyChange(changes);
final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged());
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index e1e4d2f..5c9fdc3 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -841,7 +841,7 @@
final int startFlags = request.startFlags;
final SafeActivityOptions options = request.activityOptions;
Task inTask = request.inTask;
- mInTaskFragment = request.inTaskFragment;
+ TaskFragment inTaskFragment = request.inTaskFragment;
int err = ActivityManager.START_SUCCESS;
// Pull the optional Ephemeral Installer-only bundle out of the options early.
@@ -1182,8 +1182,8 @@
}
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
- request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
- restrictedBgActivity, intentGrants);
+ request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,
+ inTask, inTaskFragment, restrictedBgActivity, intentGrants);
if (request.outActivity != null) {
request.outActivity[0] = mLastStartActivityRecord;
@@ -1553,9 +1553,10 @@
* Here also ensures that the starting activity is removed if the start wasn't successful.
*/
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- int startFlags, boolean doResume, ActivityOptions options, Task inTask,
- boolean restrictedBgActivity, NeededUriGrants intentGrants) {
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ int startFlags, boolean doResume, ActivityOptions options, Task inTask,
+ TaskFragment inTaskFragment, boolean restrictedBgActivity,
+ NeededUriGrants intentGrants) {
int result = START_CANCELED;
final Task startedActivityRootTask;
@@ -1580,7 +1581,8 @@
mService.deferWindowLayout();
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
- startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
+ startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity,
+ intentGrants);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
startedActivityRootTask = handleStartResult(r, result);
@@ -1618,7 +1620,7 @@
mTargetTask, remoteTransition);
} else if (started) {
// Make the collecting transition wait until this request is ready.
- mService.getTransitionController().setReady(false);
+ mService.getTransitionController().setReady(r, false);
}
}
}
@@ -1683,9 +1685,10 @@
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
- boolean restrictedBgActivity, NeededUriGrants intentGrants) {
- setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
- voiceInteractor, restrictedBgActivity);
+ TaskFragment inTaskFragment, boolean restrictedBgActivity,
+ NeededUriGrants intentGrants) {
+ setInitialState(r, options, inTask, inTaskFragment, doResume, startFlags, sourceRecord,
+ voiceSession, voiceInteractor, restrictedBgActivity);
computeLaunchingTaskFlags();
@@ -2253,9 +2256,9 @@
}
private void setInitialState(ActivityRecord r, ActivityOptions options, Task inTask,
- boolean doResume, int startFlags, ActivityRecord sourceRecord,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- boolean restrictedBgActivity) {
+ TaskFragment inTaskFragment, boolean doResume, int startFlags,
+ ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession,
+ IVoiceInteractor voiceInteractor, boolean restrictedBgActivity) {
reset(false /* clearRequest */);
mStartActivity = r;
@@ -2358,6 +2361,7 @@
Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
mInTask = null;
}
+ mInTaskFragment = inTaskFragment;
mStartFlags = startFlags;
// If the onlyIfNeeded flag is set, then we can do this if the activity being launched
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index e1819d3..eba3e85 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1880,25 +1880,42 @@
@Override
public void setFocusedTask(int taskId) {
enforceTaskPermission("setFocusedTask()");
- ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedTask: taskId=%d", taskId);
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_ATTACHED_TASK_ONLY);
- if (task == null) {
- return;
- }
- final ActivityRecord r = task.topRunningActivityLocked();
- if (r != null && r.moveFocusableActivityToTop("setFocusedTask")) {
- mRootWindowContainer.resumeFocusedTasksTopActivities();
- }
+ setFocusedTask(taskId, null /* touchedActivity */);
}
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
+ void setFocusedTask(int taskId, ActivityRecord touchedActivity) {
+ ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedTask: taskId=%d touchedActivity=%s", taskId,
+ touchedActivity);
+ final Task task = mRootWindowContainer.anyTaskForId(taskId, MATCH_ATTACHED_TASK_ONLY);
+ if (task == null) {
+ return;
+ }
+ final ActivityRecord r = task.topRunningActivityLocked();
+ if (r == null) {
+ return;
+ }
+
+ if (r.moveFocusableActivityToTop("setFocusedTask")) {
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
+ } else if (touchedActivity != null && touchedActivity != r
+ && touchedActivity.getTask() == r.getTask()
+ && touchedActivity.getTaskFragment() != r.getTaskFragment()) {
+ // Set the focused app directly since the focused window is not on the
+ // top-most TaskFragment of the top-most Task
+ final DisplayContent displayContent = touchedActivity.getDisplayContent();
+ displayContent.setFocusedApp(touchedActivity);
+ mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
+ true /* updateInputWindows */);
+ }
+ }
+
@Override
public boolean removeTask(int taskId) {
mAmInternal.enforceCallingPermission(REMOVE_TASKS, "removeTask()");
@@ -6507,12 +6524,7 @@
Slog.w(TAG, "Override application configuration: cannot find pid " + mPid);
return;
}
- if (wpc.getNightMode() == mNightMode) {
- return;
- }
- if (!wpc.setOverrideNightMode(mNightMode)) {
- return;
- }
+ wpc.setOverrideNightMode(mNightMode);
wpc.updateNightModeForAllActivities(mNightMode);
mPackageConfigPersister.updateFromImpl(wpc.mName, wpc.mUserId, this);
} finally {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 08bca35..f6cca84 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -347,6 +347,12 @@
*/
private int mVisibilityTransactionDepth;
+ /**
+ * Whether to the visibility updates that started from {@code RootWindowContainer} should be
+ * deferred.
+ */
+ private boolean mDeferRootVisibilityUpdate;
+
private ActivityMetricsLogger mActivityMetricsLogger;
/** Check if placing task or activity on specified display is allowed. */
@@ -1353,7 +1359,8 @@
}
mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_TO_FRONT,
- 0 /* flags */, task, options != null ? options.getRemoteTransition() : null);
+ 0 /* flags */, task, task /* readyGroupRef */,
+ options != null ? options.getRemoteTransition() : null);
reason = reason + " findTaskToMoveToFront";
boolean reparented = false;
if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) {
@@ -2263,6 +2270,14 @@
return mVisibilityTransactionDepth > 0;
}
+ void setDeferRootVisibilityUpdate(boolean deferUpdate) {
+ mDeferRootVisibilityUpdate = deferUpdate;
+ }
+
+ boolean isRootVisibilityUpdateDeferred() {
+ return mDeferRootVisibilityUpdate;
+ }
+
/**
* Called when the state or visibility of an attached activity is changed.
*
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 2eeabf2..6fafc02 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -550,8 +550,8 @@
* @return true if the nightMode has been changed.
*/
public boolean setOverrideNightMode(int nightMode) {
- final int currentUiMode = mFullConfiguration.uiMode;
- final int currentNightMode = getNightMode();
+ final int currentUiMode = mRequestedOverrideConfiguration.uiMode;
+ final int currentNightMode = currentUiMode & Configuration.UI_MODE_NIGHT_MASK;
final int validNightMode = nightMode & Configuration.UI_MODE_NIGHT_MASK;
if (currentNightMode == validNightMode) {
return false;
@@ -563,10 +563,6 @@
return true;
}
- int getNightMode() {
- return mFullConfiguration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
- }
-
public boolean isActivityTypeDream() {
return getActivityType() == ACTIVITY_TYPE_DREAM;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0889fd6..ed84411 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -772,6 +772,12 @@
mTmpWindow = null;
return true;
}
+
+ if (focusedApp.getTask() == activity.getTask()
+ && focusedApp.getTaskFragment() != activity.getTaskFragment()) {
+ // Do not use the activity window of another TaskFragment in the same leaf Task
+ return false;
+ }
}
ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: Found new focus @ %s", w);
@@ -2981,7 +2987,10 @@
@Override
void removeIfPossible() {
- if (isAnimating(TRANSITION | PARENTS)) {
+ if (isAnimating(TRANSITION | PARENTS)
+ // isAnimating is a legacy transition query and will be removed, so also add a
+ // check for whether this is in a shell-transition when not using legacy.
+ || mAtmService.getTransitionController().inTransition()) {
mDeferredRemoval = true;
return;
}
@@ -4983,7 +4992,7 @@
@WindowManager.TransitionFlags int flags) {
prepareAppTransition(transit, flags);
mAtmService.getTransitionController().requestTransitionIfNeeded(transit, flags,
- null /* trigger */);
+ null /* trigger */, this);
}
/** @see #requestTransitionAndLegacyPrepare(int, int) */
@@ -4991,11 +5000,11 @@
@Nullable WindowContainer trigger) {
prepareAppTransition(transit);
mAtmService.getTransitionController().requestTransitionIfNeeded(transit, 0 /* flags */,
- trigger);
+ trigger, this);
}
void executeAppTransition() {
- mAtmService.getTransitionController().setReady();
+ mAtmService.getTransitionController().setReady(this);
if (mAppTransition.isTransitionSet()) {
ProtoLog.w(WM_DEBUG_APP_TRANSITIONS,
"Execute app transition: %s, displayId: %d Callers=%s",
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 9ceee4b..08c8fe6 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -175,6 +175,7 @@
import com.android.server.wm.InputMonitor.EventReceiverInputConsumer;
import java.io.PrintWriter;
+import java.util.Objects;
import java.util.function.Consumer;
/**
@@ -322,17 +323,19 @@
// needs to be opaque.
private WindowState mNavBarBackgroundWindow;
+ private String mFocusedApp;
private int mLastDisableFlags;
private int mLastAppearance;
private int mLastFullscreenAppearance;
private int mLastDockedAppearance;
private int mLastBehavior;
+ private final InsetsState mRequestedState = new InsetsState();
private final Rect mNonDockedRootTaskBounds = new Rect();
private final Rect mDockedRootTaskBounds = new Rect();
private final Rect mLastNonDockedRootTaskBounds = new Rect();
private final Rect mLastDockedRootTaskBounds = new Rect();
- // What we last reported to system UI about whether the focused window is fullscreen/immersive.
+ // What we last reported to input dispatcher about whether the focused window is fullscreen.
private boolean mLastFocusIsFullscreen = false;
// If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
@@ -1645,6 +1648,10 @@
layoutStatusBar(displayFrames, mBarContentFrames.get(TYPE_STATUS_BAR));
return;
}
+ if (win.mActivityRecord != null && win.mActivityRecord.mWaitForEnteringPinnedMode) {
+ // Skip layout of the window when in transition to pip mode.
+ return;
+ }
final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation);
final int type = attrs.type;
@@ -2686,6 +2693,8 @@
&& mLastFullscreenAppearance == fullscreenAppearance
&& mLastDockedAppearance == dockedAppearance
&& mLastBehavior == behavior
+ && mRequestedState.equals(win.getRequestedState())
+ && Objects.equals(mFocusedApp, win.mAttrs.packageName)
&& mLastFocusIsFullscreen == isFullscreen
&& mLastNonDockedRootTaskBounds.equals(mNonDockedRootTaskBounds)
&& mLastDockedRootTaskBounds.equals(mDockedRootTaskBounds)) {
@@ -2701,6 +2710,8 @@
mLastFullscreenAppearance = fullscreenAppearance;
mLastDockedAppearance = dockedAppearance;
mLastBehavior = behavior;
+ mRequestedState.set(win.getRequestedState(), true /* copySources */);
+ mFocusedApp = win.mAttrs.packageName;
mLastFocusIsFullscreen = isFullscreen;
mLastNonDockedRootTaskBounds.set(mNonDockedRootTaskBounds);
mLastDockedRootTaskBounds.set(mDockedRootTaskBounds);
@@ -2719,7 +2730,7 @@
final int displayId = getDisplayId();
statusBar.setDisableFlags(displayId, disableFlags, cause);
statusBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
- isNavbarColorManagedByIme, behavior, isFullscreen);
+ isNavbarColorManagedByIme, behavior, mRequestedState, mFocusedApp);
}
});
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 737ef33..9e147b1 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -952,7 +952,8 @@
"cleanupAnimation(): Notify animation finished mPendingAnimations=%d "
+ "reorderMode=%d",
mPendingAnimations.size(), reorderMode);
- if (reorderMode != REORDER_MOVE_TO_ORIGINAL_POSITION) {
+ if (reorderMode != REORDER_MOVE_TO_ORIGINAL_POSITION
+ && mTargetActivityRecord != mDisplayContent.topRunningActivity()) {
// Notify the state at the beginning because the removeAnimation may notify the
// transition is finished. This is a signal that there will be a next transition.
mDisplayContent.mFixedRotationTransitionListener.notifyRecentsWillBeTop();
@@ -1029,7 +1030,13 @@
@Override
public void binderDied() {
- cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
+ if (!mCanceled) {
+ cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
+ } else {
+ // If we are already canceled but with a screenshot, and are waiting for the
+ // cleanupScreenshot() callback, then force-finish the animation now
+ continueDeferredCancelAnimation();
+ }
synchronized (mService.getWindowManagerLock()) {
// Clear associated input consumers on runner death
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 539bea2..bd00751 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -508,6 +508,11 @@
mTaskSupervisor.updateTopResumedActivityIfNeeded();
}
+ @Override
+ boolean isAttached() {
+ return true;
+ }
+
/**
* Called when DisplayWindowSettings values may change.
*/
@@ -1973,7 +1978,8 @@
*/
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
boolean preserveWindows, boolean notifyClients) {
- if (mTaskSupervisor.inActivityVisibilityUpdate()) {
+ if (mTaskSupervisor.inActivityVisibilityUpdate()
+ || mTaskSupervisor.isRootVisibilityUpdateDeferred()) {
// Don't do recursive work.
return;
}
@@ -2191,6 +2197,7 @@
// from doing work and changing the activity visuals while animating
// TODO(task-org): Figure-out more structured way to do this long term.
r.setWindowingMode(intermediateWindowingMode);
+ r.mWaitForEnteringPinnedMode = true;
rootTask.setWindowingMode(WINDOWING_MODE_PINNED);
rootTask.setDeferTaskAppear(false);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 88c0821..e8b6967 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -54,6 +54,8 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.SurfaceControl.METADATA_TASK_ID;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
@@ -3335,6 +3337,7 @@
info.positionInParent = getRelativePosition();
info.pictureInPictureParams = getPictureInPictureParams(top);
+ info.displayCutoutInsets = getDisplayCutoutInsets(top);
info.topActivityInfo = mReuseActivitiesReport.top != null
? mReuseActivitiesReport.top.info
: null;
@@ -3365,9 +3368,21 @@
private @Nullable PictureInPictureParams getPictureInPictureParams(Task top) {
if (top == null) return null;
- final ActivityRecord topVisibleActivity = top.getTopVisibleActivity();
- return (topVisibleActivity == null || topVisibleActivity.pictureInPictureArgs.empty())
- ? null : new PictureInPictureParams(topVisibleActivity.pictureInPictureArgs);
+ final ActivityRecord topMostActivity = top.getTopMostActivity();
+ return (topMostActivity == null || topMostActivity.pictureInPictureArgs.empty())
+ ? null : new PictureInPictureParams(topMostActivity.pictureInPictureArgs);
+ }
+
+ private Rect getDisplayCutoutInsets(Task top) {
+ if (top == null || top.mDisplayContent == null
+ || top.getDisplayInfo().displayCutout == null) return null;
+ final WindowState w = top.getTopVisibleAppMainWindow();
+ final int displayCutoutMode = w == null
+ ? WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
+ : w.getAttrs().layoutInDisplayCutoutMode;
+ return (displayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ || displayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES)
+ ? null : top.getDisplayInfo().displayCutout.getSafeInsets();
}
/**
@@ -4500,8 +4515,10 @@
mAtmService.continueWindowLayout();
}
- mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
- mRootWindowContainer.resumeFocusedTasksTopActivities();
+ if (!mTaskSupervisor.isRootVisibilityUpdateDeferred()) {
+ mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
+ }
}
void resumeNextFocusAfterReparent() {
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 25d3033..12ad634 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -205,6 +205,13 @@
@Nullable
private IBinder mFragmentToken;
+ /**
+ * The PID of the organizer that created this TaskFragment. It should be the same as the PID
+ * of {@link android.window.TaskFragmentCreationParams#getOwnerToken()}.
+ * {@link ActivityRecord#INVALID_PID} if this is not an organizer-created TaskFragment.
+ */
+ private int mTaskFragmentOrganizerPid = ActivityRecord.INVALID_PID;
+
private final Rect mTmpInsets = new Rect();
private final Rect mTmpBounds = new Rect();
private final Rect mTmpFullBounds = new Rect();
@@ -271,8 +278,9 @@
taskFragment.mAdjacentTaskFragment = this;
}
- void setTaskFragmentOrganizer(ITaskFragmentOrganizer organizer) {
+ void setTaskFragmentOrganizer(ITaskFragmentOrganizer organizer, int pid) {
mTaskFragmentOrganizer = organizer;
+ mTaskFragmentOrganizerPid = pid;
}
TaskFragment getAdjacentTaskFragment() {
@@ -1991,12 +1999,23 @@
* called from {@link Task}.
*/
TaskFragmentInfo getTaskFragmentInfo() {
+ List<IBinder> childActivities = new ArrayList<>();
+ for (int i = 0; i < getChildCount(); i++) {
+ WindowContainer wc = getChildAt(i);
+ if (mTaskFragmentOrganizerPid != ActivityRecord.INVALID_PID
+ && wc.asActivityRecord() != null
+ && wc.asActivityRecord().getPid() == mTaskFragmentOrganizerPid) {
+ // Only includes Activities that belong to the organizer process for security.
+ childActivities.add(wc.asActivityRecord().appToken);
+ }
+ }
return new TaskFragmentInfo(
mFragmentToken,
mRemoteToken.toWindowContainerToken(),
getConfiguration(),
getChildCount() == 0,
- isVisible());
+ isVisible(),
+ childActivities);
}
@Nullable
@@ -2004,6 +2023,12 @@
return mFragmentToken;
}
+ @Nullable
+ @VisibleForTesting
+ ITaskFragmentOrganizer getTaskFragmentOrganizer() {
+ return mTaskFragmentOrganizer;
+ }
+
/** Clear {@link #mLastPausedActivity} for all {@link TaskFragment} children */
void clearLastPausedActivity() {
forAllTaskFragments(taskFragment -> taskFragment.mLastPausedActivity = null);
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 1423272..56d29de 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -203,7 +203,7 @@
tf.getName(), parent.mTaskId);
try {
organizer.onTaskFragmentParentInfoChanged(tf.getFragmentToken(), parentConfig);
- mLastSentTaskFragmentParentConfigs.put(tf, parentConfig);
+ mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig));
} catch (RemoteException e) {
Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 0a8a937..65b7553 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -132,7 +132,7 @@
private TransitionInfo.AnimationOptions mOverrideOptions;
private @TransitionState int mState = STATE_COLLECTING;
- private boolean mReadyCalled = false;
+ private final ReadyTracker mReadyTracker = new ReadyTracker();
// TODO(b/188595497): remove when not needed.
/** @see RecentsAnimationController#mNavigationBarAttachedToApp */
@@ -169,9 +169,7 @@
mState = STATE_STARTED;
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Starting Transition %d",
mSyncId);
- if (mReadyCalled) {
- setReady();
- }
+ applyReady();
}
/**
@@ -186,6 +184,11 @@
for (WindowContainer curr = wc.getParent(); curr != null && !mChanges.containsKey(curr);
curr = curr.getParent()) {
mChanges.put(curr, new ChangeInfo(curr));
+ if (isReadyGroup(curr)) {
+ mReadyTracker.addGroup(curr);
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " Creating Ready-group for"
+ + " Transition %d with root=%s", mSyncId, curr);
+ }
}
if (mParticipants.contains(wc)) return;
mSyncEngine.addToSyncSet(mSyncId, wc);
@@ -236,21 +239,33 @@
* all participants have finished drawing, the transition can still collect participants.
*
* If this is called before the transition is started, it will be deferred until start.
+ *
+ * @param wc A reference point to determine which ready-group to update. For now, each display
+ * has its own ready-group, so this is used to look-up which display to mark ready.
+ * The transition will wait for all groups to be ready.
*/
- void setReady(boolean ready) {
+ void setReady(WindowContainer wc, boolean ready) {
if (mSyncId < 0) return;
- if (mState < STATE_STARTED) {
- mReadyCalled = ready;
- return;
- }
+ mReadyTracker.setReadyFrom(wc, ready);
+ applyReady();
+ }
+
+ private void applyReady() {
+ if (mState < STATE_STARTED) return;
+ final boolean ready = mReadyTracker.allReady();
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
"Set transition ready=%b %d", ready, mSyncId);
mSyncEngine.setReady(mSyncId, ready);
}
- /** @see #setReady . This calls with parameter true. */
- void setReady() {
- setReady(true);
+ /**
+ * Sets all possible ready groups to ready.
+ * @see ReadyTracker#setAllReady.
+ */
+ void setAllReady() {
+ if (mSyncId < 0) return;
+ mReadyTracker.setAllReady();
+ applyReady();
}
/**
@@ -305,17 +320,27 @@
final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
if (ar != null) {
if (!ar.isVisibleRequested()) {
- // If activity is capable of entering PiP, give it a chance to enter it now.
+ boolean commitVisibility = true;
if (ar.getDeferHidingClient() && ar.getTask() != null) {
- mController.mAtm.mTaskSupervisor.mUserLeaving = true;
- ar.getTaskFragment().startPausing(false /* uiSleeping */,
- null /* resuming */, "finishTransition");
- mController.mAtm.mTaskSupervisor.mUserLeaving = false;
+ if (ar.pictureInPictureArgs != null
+ && ar.pictureInPictureArgs.isAutoEnterEnabled()) {
+ mController.mAtm.enterPictureInPictureMode(ar, ar.pictureInPictureArgs);
+ // Avoid commit visibility to false here, or else we will get a sudden
+ // "flash" / surface going invisible for a split second.
+ commitVisibility = false;
+ } else {
+ mController.mAtm.mTaskSupervisor.mUserLeaving = true;
+ ar.getTaskFragment().startPausing(false /* uiSleeping */,
+ null /* resuming */, "finishTransition");
+ mController.mAtm.mTaskSupervisor.mUserLeaving = false;
+ }
}
- ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
- " Commit activity becoming invisible: %s", ar);
- ar.commitVisibility(false /* visible */, false /* performLayout */);
- activitiesWentInvisible = true;
+ if (commitVisibility) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " Commit activity becoming invisible: %s", ar);
+ ar.commitVisibility(false /* visible */, false /* performLayout */);
+ activitiesWentInvisible = true;
+ }
}
if (mChanges.get(ar).mVisible != ar.isVisibleRequested()) {
// Legacy dispatch relies on this (for now).
@@ -881,6 +906,15 @@
}
/**
+ * A ready group is defined by a root window-container where all transitioning windows under
+ * it are expected to animate together as a group. At the moment, this treats each display as
+ * a ready-group to match the existing legacy transition behavior.
+ */
+ private static boolean isReadyGroup(WindowContainer wc) {
+ return wc instanceof DisplayContent;
+ }
+
+ /**
* Construct a TransitionInfo object from a set of targets and changes. Also populates the
* root surface.
*/
@@ -1082,4 +1116,95 @@
mChildren.addAll(wcs);
}
}
+
+ /**
+ * The transition sync mechanism has 2 parts:
+ * 1. Whether all WM operations for a particular transition are "ready" (eg. did the app
+ * launch or stop or get a new configuration?).
+ * 2. Whether all the windows involved have finished drawing their final-state content.
+ *
+ * A transition animation can play once both parts are complete. This ready-tracker keeps track
+ * of part (1). Currently, WM code assumes that "readiness" (part 1) is grouped. This means that
+ * even if the WM operations in one group are ready, the whole transition itself may not be
+ * ready if there are WM operations still pending in another group. This class helps keep track
+ * of readiness across the multiple groups. Currently, we assume that each display is a group
+ * since that is how it has been until now.
+ */
+ private static class ReadyTracker {
+ private final ArrayMap<WindowContainer, Boolean> mReadyGroups = new ArrayMap<>();
+
+ /**
+ * Ensures that this doesn't report as allReady before it has been used. This is needed
+ * in very niche cases where a transition is a no-op (nothing has been collected) but we
+ * still want to be marked ready (via. setAllReady).
+ */
+ private boolean mUsed = false;
+
+ /**
+ * If true, this overrides all ready groups and reports ready. Used by shell-initiated
+ * transitions via {@link #setAllReady()}.
+ */
+ private boolean mReadyOverride = false;
+
+ /**
+ * Adds a ready-group. Any setReady calls in this subtree will be tracked together. For
+ * now these are only DisplayContents.
+ */
+ void addGroup(WindowContainer wc) {
+ if (mReadyGroups.containsKey(wc)) {
+ Slog.e(TAG, "Trying to add a ready-group twice: " + wc);
+ return;
+ }
+ mReadyGroups.put(wc, false);
+ }
+
+ /**
+ * Sets a group's ready state.
+ * @param wc Any container within a group's subtree. Used to identify the ready-group.
+ */
+ void setReadyFrom(WindowContainer wc, boolean ready) {
+ mUsed = true;
+ WindowContainer current = wc;
+ while (current != null) {
+ if (isReadyGroup(current)) {
+ mReadyGroups.put(current, ready);
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " Setting Ready-group to"
+ + " %b. group=%s from %s", ready, current, wc);
+ break;
+ }
+ current = current.getParent();
+ }
+ }
+
+ /** Marks this as ready regardless of individual groups. */
+ void setAllReady() {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " Setting allReady override");
+ mUsed = true;
+ mReadyOverride = true;
+ }
+
+ /** @return true if all tracked subtrees are ready. */
+ boolean allReady() {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " allReady query: used=%b "
+ + "override=%b states=[%s]", mUsed, mReadyOverride, groupsToString());
+ if (!mUsed) return false;
+ if (mReadyOverride) return true;
+ for (int i = mReadyGroups.size() - 1; i >= 0; --i) {
+ final WindowContainer wc = mReadyGroups.keyAt(i);
+ if (!wc.isAttached() || !wc.isVisibleRequested()) continue;
+ if (!mReadyGroups.valueAt(i)) return false;
+ }
+ return true;
+ }
+
+ private String groupsToString() {
+ StringBuilder b = new StringBuilder();
+ for (int i = 0; i < mReadyGroups.size(); ++i) {
+ if (i != 0) b.append(',');
+ b.append(mReadyGroups.keyAt(i)).append(':')
+ .append(mReadyGroups.valueAt(i));
+ }
+ return b.toString();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 3d7b34b..16d2278 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -192,8 +192,8 @@
*/
@Nullable
Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
- @Nullable WindowContainer trigger) {
- return requestTransitionIfNeeded(type, 0 /* flags */, trigger);
+ @NonNull WindowContainer trigger) {
+ return requestTransitionIfNeeded(type, 0 /* flags */, trigger, trigger /* readyGroupRef */);
}
/**
@@ -201,8 +201,10 @@
*/
@Nullable
Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
- @WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger) {
- return requestTransitionIfNeeded(type, flags, trigger, null /* remote */);
+ @WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger,
+ @NonNull WindowContainer readyGroupRef) {
+ return requestTransitionIfNeeded(type, flags, trigger, readyGroupRef,
+ null /* remoteTransition */);
}
private static boolean isExistenceType(@WindowManager.TransitionType int type) {
@@ -213,19 +215,20 @@
* If a transition isn't requested yet, creates one and asks the TransitionPlayer (Shell) to
* start it. Collection can start immediately.
* @param trigger if non-null, this is the first container that will be collected
+ * @param readyGroupRef Used to identify which ready-group this request is for.
* @return the created transition if created or null otherwise.
*/
@Nullable
Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
@WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger,
- @Nullable IRemoteTransition remoteTransition) {
+ @NonNull WindowContainer readyGroupRef, @Nullable IRemoteTransition remoteTransition) {
if (mTransitionPlayer == null) {
return null;
}
Transition newTransition = null;
if (isCollecting()) {
// Make the collecting transition wait until this request is ready.
- mCollectingTransition.setReady(false);
+ mCollectingTransition.setReady(readyGroupRef, false);
} else {
newTransition = requestStartTransition(createTransition(type, flags),
trigger != null ? trigger.asTask() : null, remoteTransition);
@@ -280,14 +283,14 @@
}
/** @see Transition#setReady */
- void setReady(boolean ready) {
+ void setReady(WindowContainer wc, boolean ready) {
if (mCollectingTransition == null) return;
- mCollectingTransition.setReady(ready);
+ mCollectingTransition.setReady(wc, ready);
}
/** @see Transition#setReady */
- void setReady() {
- setReady(true);
+ void setReady(WindowContainer wc) {
+ setReady(wc, true);
}
/** @see Transition#finishTransition */
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 913c5e5..ffee0b7 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -851,7 +851,8 @@
}
boolean isAttached() {
- return getDisplayArea() != null;
+ WindowContainer parent = getParent();
+ return parent != null && parent.isAttached();
}
void setWaitingForDrawnIfResizingChanged() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f9e6559..16e28d4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2720,8 +2720,8 @@
}
@Override
- public boolean attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId,
- Bundle options) {
+ public Configuration attachWindowContextToDisplayArea(IBinder clientToken, int
+ type, int displayId, Bundle options) {
final boolean callerCanManageAppTokens = checkCallingPermission(MANAGE_APP_TOKENS,
"attachWindowContextToDisplayArea", false /* printLog */);
final int callingUid = Binder.getCallingUid();
@@ -2732,15 +2732,17 @@
if (dc == null) {
ProtoLog.w(WM_ERROR, "attachWindowContextToDisplayArea: trying to attach"
+ " to a non-existing display:%d", displayId);
- return false;
+ return null;
}
// TODO(b/155340867): Investigate if we still need roundedCornerOverlay after
// the feature b/155340867 is completed.
final DisplayArea da = dc.findAreaForWindowType(type, options,
callerCanManageAppTokens, false /* roundedCornerOverlay */);
+ // TODO(b/190019118): Avoid to send onConfigurationChanged because it has been done
+ // in return value of attachWindowContextToDisplayArea.
mWindowContextListenerController.registerWindowContainerListener(clientToken, da,
callingUid, type, options);
- return true;
+ return da.getConfiguration();
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -8130,7 +8132,11 @@
|| mRoot.isAnimating(TRANSITION | CHILDREN, ANIMATION_TYPE_ALL)
|| animateStarting;
if (!isAnimating) {
- break;
+ // isAnimating is a legacy transition query and will be removed, so also add
+ // a check for whether this is in a shell-transition when not using legacy.
+ if (!mAtmService.getTransitionController().inTransition()) {
+ break;
+ }
}
long startTime = System.currentTimeMillis();
try {
@@ -8193,11 +8199,11 @@
displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, displayContent,
true /* includingParents */);
}
- handleTaskFocusChange(touchedWindow.getTask());
+ handleTaskFocusChange(touchedWindow.getTask(), touchedWindow.mActivityRecord);
}
@VisibleForTesting
- void handleTaskFocusChange(Task task) {
+ void handleTaskFocusChange(Task task, ActivityRecord touchedActivity) {
if (task == null) {
return;
}
@@ -8216,7 +8222,7 @@
}
}
- mAtmService.setFocusedTask(task.mTaskId);
+ mAtmService.setFocusedTask(task.mTaskId, touchedActivity);
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index b82819c..4fa3aab 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -227,7 +227,7 @@
}
applyTransaction(t, -1 /*syncId*/, transition, caller);
if (needsSetReady) {
- transition.setReady();
+ transition.setAllReady();
}
return transition;
}
@@ -275,6 +275,7 @@
int effects = 0;
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
mService.deferWindowLayout();
+ mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */);
try {
if (transition != null) {
// First check if we have a display rotation transition and if so, update it.
@@ -363,6 +364,7 @@
task.setMainWindowSizeChangeTransaction(sft);
}
if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
+ mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
// Already calls ensureActivityConfig
mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
mService.mRootWindowContainer.resumeFocusedTasksTopActivities();
@@ -384,6 +386,7 @@
mService.addWindowLayoutReasons(LAYOUT_REASON_CONFIG_CHANGED);
}
} finally {
+ mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
mService.continueWindowLayout();
}
}
@@ -921,7 +924,8 @@
ownerActivity.getTask().addChild(taskFragment, POSITION_TOP);
taskFragment.setWindowingMode(creationParams.getWindowingMode());
taskFragment.setBounds(creationParams.getInitialBounds());
- taskFragment.setTaskFragmentOrganizer(creationParams.getOrganizer());
+ taskFragment.setTaskFragmentOrganizer(
+ creationParams.getOrganizer(), ownerActivity.getPid());
mLaunchTaskFragments.put(creationParams.getFragmentToken(), taskFragment);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8443c92..3abe455 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -875,6 +875,15 @@
}
/**
+ * Returns all the requested visibilities.
+ *
+ * @return an {@link InsetsState} as the requested visibilities.
+ */
+ InsetsState getRequestedState() {
+ return mRequestedInsetsState;
+ }
+
+ /**
* @see #getRequestedVisibility(int)
*/
void updateRequestedVisibility(InsetsState state) {
@@ -2394,6 +2403,12 @@
@Override
void removeImmediately() {
+ if (!mRemoved) {
+ // Destroy surface before super call. The general pattern is that the children need
+ // to be removed before the parent (so that the sync-engine tracking works). Since
+ // WindowStateAnimator is a "virtual" child, we have to do it manually here.
+ mWinAnimator.destroySurfaceLocked(getSyncTransaction());
+ }
super.removeImmediately();
if (mRemoved) {
@@ -2435,8 +2450,6 @@
disposeInputChannel();
- mWinAnimator.destroySurfaceLocked(mTmpTransaction);
- mTmpTransaction.apply();
mSession.windowRemovedLocked();
try {
mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index fd71d1b..e9babce 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -14991,9 +14991,9 @@
}
private void setNetworkLoggingActiveInternal(boolean active) {
- final boolean[] shouldSendNotification = new boolean[] {false};
- synchronized (getLockObject()) {
- mInjector.binderWithCleanCallingIdentity(() -> {
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ boolean shouldSendNotification = false;
+ synchronized (getLockObject()) {
if (active) {
if (mNetworkLogger == null) {
final int affectedUserId = getNetworkLoggingAffectedUser();
@@ -15008,7 +15008,7 @@
+ " service not being available yet.");
}
maybePauseDeviceWideLoggingLocked();
- shouldSendNotification[0] = shouldSendNetworkLoggingNotificationLocked();
+ shouldSendNotification = shouldSendNetworkLoggingNotificationLocked();
} else {
if (mNetworkLogger != null && !mNetworkLogger.stopNetworkLogging()) {
Slogf.wtf(LOG_TAG, "Network logging could not be stopped due to the logging"
@@ -15016,15 +15016,15 @@
}
mNetworkLogger = null;
}
- });
- }
- if (active) {
- if (shouldSendNotification[0]) {
- sendNetworkLoggingNotification();
}
- } else {
- mInjector.getNotificationManager().cancel(SystemMessage.NOTE_NETWORK_LOGGING);
- }
+ if (active) {
+ if (shouldSendNotification) {
+ sendNetworkLoggingNotification();
+ }
+ } else {
+ mInjector.getNotificationManager().cancel(SystemMessage.NOTE_NETWORK_LOGGING);
+ }
+ });
}
private @UserIdInt int getNetworkLoggingAffectedUser() {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a6ea585..763b74b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -376,6 +376,8 @@
"com.android.server.connectivity.IpConnectivityMetrics";
private static final String MEDIA_COMMUNICATION_SERVICE_CLASS =
"com.android.server.media.MediaCommunicationService";
+ private static final String APP_COMPAT_OVERRIDES_SERVICE_CLASS =
+ "com.android.server.compat.overrides.AppCompatOverridesService$Lifecycle";
private static final String ROLE_SERVICE_CLASS = "com.android.role.RoleService";
private static final String GAME_MANAGER_SERVICE_CLASS =
@@ -2648,6 +2650,10 @@
mSystemServiceManager.startService(MEDIA_COMMUNICATION_SERVICE_CLASS);
t.traceEnd();
+ t.traceBegin("AppCompatOverridesService");
+ mSystemServiceManager.startService(APP_COMPAT_OVERRIDES_SERVICE_CLASS);
+ t.traceEnd();
+
ConcurrentUtils.waitForFutureNoInterrupt(mBlobStoreServiceStart,
START_BLOB_STORE_SERVICE);
diff --git a/services/net/Android.bp b/services/net/Android.bp
index a822257..21964dd 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -23,7 +23,6 @@
],
static_libs: [
"netd-client",
- "netlink-client",
"networkstack-client",
"net-utils-services-common",
],
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 583797e..a254f68 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -514,8 +514,16 @@
}
private void setAllowWhileIdleAlarm(int type, long triggerTime, PendingIntent pi,
- boolean unrestricted) {
- final int flags = unrestricted ? FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED : FLAG_ALLOW_WHILE_IDLE;
+ boolean unrestricted, boolean compat) {
+ assertFalse("Alarm cannot be compat and unrestricted", unrestricted && compat);
+ final int flags;
+ if (unrestricted) {
+ flags = FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
+ } else if (compat) {
+ flags = FLAG_ALLOW_WHILE_IDLE_COMPAT;
+ } else {
+ flags = FLAG_ALLOW_WHILE_IDLE;
+ }
setTestAlarm(type, triggerTime, pi, 0, flags, TEST_CALLING_UID);
}
@@ -1600,13 +1608,13 @@
final long firstTrigger = mNowElapsedTest + 10;
for (int i = 0; i < quota; i++) {
setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i,
- getNewMockPendingIntent(), false);
+ getNewMockPendingIntent(), false, false);
mNowElapsedTest = mTestTimer.getElapsed();
mTestTimer.expire();
}
// This one should get deferred on set.
setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + quota,
- getNewMockPendingIntent(), false);
+ getNewMockPendingIntent(), false, false);
final long expectedNextTrigger = firstTrigger + mAllowWhileIdleWindow;
assertEquals("Incorrect trigger when no quota left", expectedNextTrigger,
mTestTimer.getElapsed());
@@ -1619,6 +1627,108 @@
}
@Test
+ public void allowWhileIdleCompatAlarmsWhileDeviceIdle() throws Exception {
+ setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);
+
+ final long window = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+ setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + window + 1000,
+ getNewMockPendingIntent());
+ assertNotNull(mService.mPendingIdleUntil);
+
+ final int quota = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
+ final long firstTrigger = mNowElapsedTest + 10;
+ for (int i = 0; i < quota; i++) {
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i,
+ getNewMockPendingIntent(), false, true);
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+ // This one should get deferred on set.
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + quota,
+ getNewMockPendingIntent(), false, true);
+ final long expectedNextTrigger = firstTrigger + window;
+ assertEquals("Incorrect trigger when no quota left", expectedNextTrigger,
+ mTestTimer.getElapsed());
+
+ // Bring the idle until alarm back.
+ setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, expectedNextTrigger - 50,
+ getNewMockPendingIntent());
+ assertEquals(expectedNextTrigger - 50, mService.mPendingIdleUntil.getWhenElapsed());
+ assertEquals(expectedNextTrigger - 50, mTestTimer.getElapsed());
+ }
+
+ @Test
+ public void allowWhileIdleCompatHistorySeparate() throws Exception {
+ when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID,
+ TEST_CALLING_PACKAGE)).thenReturn(true);
+ when(mAppStateTracker.isForceAllAppsStandbyEnabled()).thenReturn(true);
+
+ final int fullQuota = mService.mConstants.ALLOW_WHILE_IDLE_QUOTA;
+ final int compatQuota = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
+
+ final long fullWindow = mAllowWhileIdleWindow;
+ final long compatWindow = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+
+ final long firstFullTrigger = mNowElapsedTest + 10;
+ for (int i = 0; i < fullQuota; i++) {
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstFullTrigger + i,
+ getNewMockPendingIntent(), false, false);
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+ // This one should get deferred on set, as full quota is not available.
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstFullTrigger + fullQuota,
+ getNewMockPendingIntent(), false, false);
+ final long expectedNextFullTrigger = firstFullTrigger + fullWindow;
+ assertEquals("Incorrect trigger when no quota left", expectedNextFullTrigger,
+ mTestTimer.getElapsed());
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+
+ // The following should be allowed, as compat quota should be free.
+ for (int i = 0; i < compatQuota; i++) {
+ final long trigger = mNowElapsedTest + 1;
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger, getNewMockPendingIntent(),
+ false, true);
+ assertEquals(trigger, mTestTimer.getElapsed());
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+
+ // Refresh the state
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+ mService.mAllowWhileIdleHistory.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER);
+ mService.mAllowWhileIdleCompatHistory.removeForPackage(TEST_CALLING_PACKAGE,
+ TEST_CALLING_USER);
+
+ // Now test with flipped order
+
+ final long firstCompatTrigger = mNowElapsedTest + 10;
+ for (int i = 0; i < compatQuota; i++) {
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstCompatTrigger + i,
+ getNewMockPendingIntent(), false, true);
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+ // This one should get deferred on set, as full quota is not available.
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstCompatTrigger + compatQuota,
+ getNewMockPendingIntent(), false, true);
+ final long expectedNextCompatTrigger = firstCompatTrigger + compatWindow;
+ assertEquals("Incorrect trigger when no quota left", expectedNextCompatTrigger,
+ mTestTimer.getElapsed());
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+
+ // The following should be allowed, as full quota should be free.
+ for (int i = 0; i < fullQuota; i++) {
+ final long trigger = mNowElapsedTest + 1;
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger, getNewMockPendingIntent(),
+ false, false);
+ assertEquals(trigger, mTestTimer.getElapsed());
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+ }
+
+ @Test
public void allowWhileIdleUnrestricted() throws Exception {
setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);
@@ -1634,7 +1744,7 @@
final long firstTrigger = mNowElapsedTest + 10;
for (int i = 0; i < numAlarms; i++) {
setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i,
- getNewMockPendingIntent(), true);
+ getNewMockPendingIntent(), true, false);
}
// All of them should fire as expected.
for (int i = 0; i < numAlarms; i++) {
@@ -1736,7 +1846,7 @@
final int quota = mService.mConstants.ALLOW_WHILE_IDLE_QUOTA;
testQuotasDeferralOnSet(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger,
- getNewMockPendingIntent(), false), quota, mAllowWhileIdleWindow);
+ getNewMockPendingIntent(), false, false), quota, mAllowWhileIdleWindow);
// Refresh the state
mService.removeLocked(TEST_CALLING_UID,
@@ -1744,7 +1854,7 @@
mService.mAllowWhileIdleHistory.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER);
testQuotasDeferralOnExpiration(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP,
- trigger, getNewMockPendingIntent(), false), quota, mAllowWhileIdleWindow);
+ trigger, getNewMockPendingIntent(), false, false), quota, mAllowWhileIdleWindow);
// Refresh the state
mService.removeLocked(TEST_CALLING_UID,
@@ -1752,7 +1862,36 @@
mService.mAllowWhileIdleHistory.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER);
testQuotasNoDeferral(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger,
- getNewMockPendingIntent(), false), quota, mAllowWhileIdleWindow);
+ getNewMockPendingIntent(), false, false), quota, mAllowWhileIdleWindow);
+ }
+
+ @Test
+ public void allowWhileIdleCompatAlarmsInBatterySaver() throws Exception {
+ when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID,
+ TEST_CALLING_PACKAGE)).thenReturn(true);
+ when(mAppStateTracker.isForceAllAppsStandbyEnabled()).thenReturn(true);
+
+ final int quota = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
+ final long window = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+
+ testQuotasDeferralOnSet(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger,
+ getNewMockPendingIntent(), false, true), quota, window);
+
+ // Refresh the state
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+ mService.mAllowWhileIdleCompatHistory.removeForPackage(TEST_CALLING_PACKAGE,
+ TEST_CALLING_USER);
+
+ testQuotasDeferralOnExpiration(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP,
+ trigger, getNewMockPendingIntent(), false, true), quota, window);
+
+ // Refresh the state
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+ mService.mAllowWhileIdleCompatHistory.removeForPackage(TEST_CALLING_PACKAGE,
+ TEST_CALLING_USER);
+
+ testQuotasNoDeferral(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger,
+ getNewMockPendingIntent(), false, true), quota, window);
}
@Test
@@ -2123,7 +2262,7 @@
final PendingIntent alarmPi = getNewMockPendingIntent();
final AlarmManager.AlarmClockInfo alarmClock = mock(AlarmManager.AlarmClockInfo.class);
mBinder.set(TEST_CALLING_PACKAGE, RTC_WAKEUP, 1234, WINDOW_EXACT, 0, 0,
- alarmPi, null, null, null, alarmClock);
+ alarmPi, null, null, null, alarmClock);
// Correct permission checks are invoked.
verify(mService).hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID);
diff --git a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java
new file mode 100644
index 0000000..bf97042
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java
@@ -0,0 +1,302 @@
+/*
+ * 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.compat.overrides;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+
+import static java.util.Collections.emptySet;
+
+import android.app.compat.PackageOverride;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.platform.test.annotations.Presubmit;
+import android.util.ArraySet;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.compat.overrides.AppCompatOverridesParser.PackageOverrides;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Test class for {@link AppCompatOverridesParser}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksMockingServicesTests:AppCompatOverridesParserTest
+ */
+@RunWith(MockitoJUnitRunner.class)
+@SmallTest
+@Presubmit
+public class AppCompatOverridesParserTest {
+ private static final String PACKAGE_1 = "com.android.test1";
+ private static final String PACKAGE_2 = "com.android.test2";
+ private static final String PACKAGE_3 = "com.android.test3";
+ private static final String PACKAGE_4 = "com.android.test4";
+
+ private AppCompatOverridesParser mParser;
+
+ @Mock
+ private PackageManager mPackageManager;
+
+ @Before
+ public void setUp() throws Exception {
+ mParser = new AppCompatOverridesParser(mPackageManager);
+ }
+
+ @Test
+ public void parseRemoveOverrides_emptyConfig_returnsEmpty() {
+ Set<Long> ownedChangeIds = new ArraySet<>(Arrays.asList(123L, 456L));
+
+ assertThat(mParser.parseRemoveOverrides("", ownedChangeIds)).isEmpty();
+ }
+
+ @Test
+ public void parseRemoveOverrides_configHasWildcardNoOwnedChangeIds_returnsEmpty() {
+ when(mPackageManager.getInstalledApplications(anyInt()))
+ .thenReturn(Arrays.asList(createAppInfo(PACKAGE_1), createAppInfo(PACKAGE_2)));
+
+ assertThat(mParser.parseRemoveOverrides("*", /* ownedChangeIds= */ emptySet())).isEmpty();
+ }
+
+ @Test
+ public void parseRemoveOverrides_configHasWildcard_returnsAllInstalledPackagesToAllOwnedIds() {
+ Set<Long> ownedChangeIds = new ArraySet<>(Arrays.asList(123L, 456L));
+ when(mPackageManager.getInstalledApplications(anyInt()))
+ .thenReturn(Arrays.asList(createAppInfo(PACKAGE_1), createAppInfo(PACKAGE_2),
+ createAppInfo(PACKAGE_3)));
+
+ Map<String, Set<Long>> result = mParser.parseRemoveOverrides("*", ownedChangeIds);
+
+ assertThat(result).hasSize(3);
+ assertThat(result.get(PACKAGE_1)).containsExactly(123L, 456L);
+ assertThat(result.get(PACKAGE_2)).containsExactly(123L, 456L);
+ assertThat(result.get(PACKAGE_3)).containsExactly(123L, 456L);
+ }
+
+ @Test
+ public void parseRemoveOverrides_configHasInvalidWildcardSymbol_returnsEmpty() {
+ Set<Long> ownedChangeIds = new ArraySet<>(Arrays.asList(123L, 456L));
+ when(mPackageManager.getInstalledApplications(anyInt())).thenReturn(
+ Arrays.asList(createAppInfo(PACKAGE_1), createAppInfo(PACKAGE_2)));
+
+ assertThat(mParser.parseRemoveOverrides("**", ownedChangeIds)).isEmpty();
+ }
+
+ @Test
+ public void parseRemoveOverrides_configHasSingleEntry_returnsPackageToChangeIds() {
+ Map<String, Set<Long>> result = mParser.parseRemoveOverrides(
+ PACKAGE_1 + "=12:34", /* ownedChangeIds= */ emptySet());
+
+ assertThat(result).hasSize(1);
+ assertThat(result.get(PACKAGE_1)).containsExactly(12L, 34L);
+ }
+
+ @Test
+ public void parseRemoveOverrides_configHasMultipleEntries_returnsPackagesToChangeIds() {
+ Set<Long> ownedChangeIds = new ArraySet<>(Arrays.asList(12L, 34L, 56L, 78L));
+
+ Map<String, Set<Long>> result = mParser.parseRemoveOverrides(
+ PACKAGE_1 + "=12," + PACKAGE_2 + "=*," + PACKAGE_3 + "=12:56:78," + PACKAGE_4
+ + "=", ownedChangeIds);
+
+ assertThat(result).hasSize(3);
+ assertThat(result.get(PACKAGE_1)).containsExactly(12L);
+ assertThat(result.get(PACKAGE_2)).containsExactly(12L, 34L, 56L, 78L);
+ assertThat(result.get(PACKAGE_3)).containsExactly(12L, 56L, 78L);
+ }
+
+ @Test
+ public void parseRemoveOverrides_configHasPackageWithWildcardNoOwnedId_returnsWithoutPackage() {
+ Map<String, Set<Long>> result = mParser.parseRemoveOverrides(
+ PACKAGE_1 + "=*," + PACKAGE_2 + "=12", /* ownedChangeIds= */ emptySet());
+
+ assertThat(result).hasSize(1);
+ assertThat(result.get(PACKAGE_2)).containsExactly(12L);
+ }
+
+ @Test
+ public void parseRemoveOverrides_configHasInvalidKeyValueListFormat_returnsEmpty() {
+ Set<Long> ownedChangeIds = new ArraySet<>(Arrays.asList(12L, 34L));
+
+ assertThat(mParser.parseRemoveOverrides(
+ PACKAGE_1 + "=12," + PACKAGE_2 + ">34", ownedChangeIds)).isEmpty();
+ }
+
+
+ @Test
+ public void parseRemoveOverrides_configHasInvalidChangeIds_returnsWithoutInvalidChangeIds() {
+ Map<String, Set<Long>> result = mParser.parseRemoveOverrides(
+ PACKAGE_1 + "=12," + PACKAGE_2 + "=12:56L:78," + PACKAGE_3
+ + "=34L", /* ownedChangeIds= */ emptySet());
+
+ assertThat(result).hasSize(2);
+ assertThat(result.get(PACKAGE_1)).containsExactly(12L);
+ assertThat(result.get(PACKAGE_2)).containsExactly(12L, 78L);
+ }
+
+ @Test
+ public void parseOwnedChangeIds_emptyConfig_returnsEmpty() {
+ assertThat(AppCompatOverridesParser.parseOwnedChangeIds("")).isEmpty();
+ }
+
+ @Test
+ public void parseOwnedChangeIds_configHasSingleChangeId_returnsChangeId() {
+ assertThat(AppCompatOverridesParser.parseOwnedChangeIds("123")).containsExactly(123L);
+ }
+
+ @Test
+ public void parseOwnedChangeIds_configHasMultipleChangeIds_returnsChangeIds() {
+ assertThat(AppCompatOverridesParser.parseOwnedChangeIds("12,34,56")).containsExactly(12L,
+ 34L, 56L);
+ }
+
+ @Test
+ public void parseOwnedChangeIds_configHasInvalidChangeIds_returnsWithoutInvalidChangeIds() {
+ // We add a valid entry before and after the invalid ones to make sure they are applied.
+ assertThat(AppCompatOverridesParser.parseOwnedChangeIds("12,C34,56")).containsExactly(12L,
+ 56L);
+ }
+
+ @Test
+ public void parsePackageOverrides_emptyConfig_returnsEmpty() {
+ PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
+ "", /* versionCode= */ 0, /* changeIdsToSkip= */ emptySet());
+
+ assertThat(result.overridesToAdd).isEmpty();
+ assertThat(result.overridesToRemove).isEmpty();
+ }
+
+ @Test
+ public void parsePackageOverrides_configWithSingleOverride_returnsOverride() {
+ PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
+ "123:::true", /* versionCode= */ 5, /* changeIdsToSkip= */ emptySet());
+
+ assertThat(result.overridesToAdd).hasSize(1);
+ assertThat(result.overridesToAdd.get(123L)).isEqualTo(
+ new PackageOverride.Builder().setEnabled(true).build());
+ }
+
+ @Test
+ public void parsePackageOverrides_configWithMultipleOverridesToAdd_returnsOverrides() {
+ PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
+ "910:3:4:false,78:10::false,12:::false,34:1:2:true,34:10::true,56::2:true,"
+ + "56:3:4:false,34:4:8:true,78:6:7:true,910:5::true,1112::5:true,"
+ + "56:6::true,1112:6:7:false", /* versionCode= */
+ 5, /* changeIdsToSkip= */ emptySet());
+
+ assertThat(result.overridesToAdd).hasSize(6);
+ assertThat(result.overridesToAdd.get(12L)).isEqualTo(
+ new PackageOverride.Builder().setEnabled(false).build());
+ assertThat(result.overridesToAdd.get(34L)).isEqualTo(
+ new PackageOverride.Builder().setMinVersionCode(4).setMaxVersionCode(8).setEnabled(
+ true).build());
+ assertThat(result.overridesToAdd.get(56L)).isEqualTo(
+ new PackageOverride.Builder().setMinVersionCode(3).setMaxVersionCode(4).setEnabled(
+ false).build());
+ assertThat(result.overridesToAdd.get(78L)).isEqualTo(
+ new PackageOverride.Builder().setMinVersionCode(6).setMaxVersionCode(7).setEnabled(
+ true).build());
+ assertThat(result.overridesToAdd.get(910L)).isEqualTo(
+ new PackageOverride.Builder().setMinVersionCode(5).setEnabled(true).build());
+ assertThat(result.overridesToAdd.get(1112L)).isEqualTo(
+ new PackageOverride.Builder().setMaxVersionCode(5).setEnabled(true).build());
+ assertThat(result.overridesToRemove).isEmpty();
+ }
+
+ @Test
+ public void parsePackageOverrides_configWithMultipleOverridesToRemove_returnsOverrides() {
+ PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
+ "12:::,34:1:2:", /* versionCode= */ 5, /* changeIdsToSkip= */ emptySet());
+
+ assertThat(result.overridesToRemove).containsExactly(12L, 34L);
+ assertThat(result.overridesToAdd).isEmpty();
+ }
+
+ @Test
+ public void parsePackageOverrides_configWithBothOverridesToAddAndRemove_returnsOverrides() {
+ // Note that change 56 is both added and removed, therefore it will only be removed.
+ PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
+ "56:::,12:::true,34:::,56:3:7:true", /* versionCode= */ 5, /* changeIdsToSkip= */
+ emptySet());
+
+ assertThat(result.overridesToAdd).hasSize(1);
+ assertThat(result.overridesToAdd.get(12L)).isEqualTo(
+ new PackageOverride.Builder().setEnabled(true).build());
+ assertThat(result.overridesToRemove).containsExactly(34L, 56L);
+ }
+
+ @Test
+ public void parsePackageOverrides_changeIdsToSkipSpecified_returnsWithoutChangeIdsToSkip() {
+ ArraySet<Long> changeIdsToSkip = new ArraySet<>();
+ changeIdsToSkip.add(34L);
+ changeIdsToSkip.add(56L);
+ changeIdsToSkip.add(910L);
+ PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
+ "12:::true,34:::,56:3:7:true,78:::", /* versionCode= */ 5, changeIdsToSkip);
+
+ assertThat(result.overridesToAdd).hasSize(1);
+ assertThat(result.overridesToAdd.get(12L)).isEqualTo(
+ new PackageOverride.Builder().setEnabled(true).build());
+ assertThat(result.overridesToRemove).containsExactly(78L);
+ }
+
+ @Test
+ public void parsePackageOverrides_changeIdsToSkipContainsAllIds_returnsEmpty() {
+ ArraySet<Long> changeIdsToSkip = new ArraySet<>();
+ changeIdsToSkip.add(12L);
+ changeIdsToSkip.add(34L);
+ PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
+ "12:::true,34:::", /* versionCode= */ 5, changeIdsToSkip);
+
+ assertThat(result.overridesToAdd).isEmpty();
+ assertThat(result.overridesToRemove).isEmpty();
+ }
+
+ @Test
+ public void parsePackageOverrides_someOverridesAreInvalid_returnsWithoutInvalidOverrides() {
+ // We add a valid entry before and after the invalid ones to make sure they are applied.
+ PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
+ "12:::True,56:1:2:FALSE,56:3:true,78:4:8:true:,C1:::true,910:::no,"
+ + "1112:1:ten:true,1112:one:10:true,,1314:7:3:false,34:one:ten:",
+ /* versionCode= */ 5, /* changeIdsToSkip= */ emptySet());
+
+ assertThat(result.overridesToAdd).hasSize(2);
+ assertThat(result.overridesToAdd.get(12L)).isEqualTo(
+ new PackageOverride.Builder().setEnabled(true).build());
+ assertThat(result.overridesToAdd.get(56L)).isEqualTo(
+ new PackageOverride.Builder().setMinVersionCode(1).setMaxVersionCode(2).setEnabled(
+ false).build());
+ assertThat(result.overridesToRemove).containsExactly(34L);
+ }
+
+ private static ApplicationInfo createAppInfo(String packageName) {
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = packageName;
+ return appInfo;
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java
new file mode 100644
index 0000000..3129272
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java
@@ -0,0 +1,688 @@
+/*
+ * 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.compat.overrides;
+
+import static android.content.Intent.ACTION_PACKAGE_ADDED;
+import static android.content.Intent.ACTION_PACKAGE_CHANGED;
+import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.ACTION_USER_SWITCHED;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_OWNED_CHANGE_IDS;
+import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_REMOVE_OVERRIDES;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.compat.PackageOverride;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
+import com.android.internal.compat.IPlatformCompat;
+import com.android.server.testables.TestableDeviceConfig.TestableDeviceConfigRule;
+
+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.junit.MockitoJUnitRunner;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * Test class for {@link AppCompatOverridesService}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksMockingServicesTests:AppCompatOverridesServiceTest
+ */
+@RunWith(MockitoJUnitRunner.class)
+@SmallTest
+@Presubmit
+public class AppCompatOverridesServiceTest {
+ private static final String NAMESPACE_1 = "namespace_1";
+ private static final String NAMESPACE_2 = "namespace_2";
+ private static final String NAMESPACE_3 = "namespace_3";
+ private static final List<String> SUPPORTED_NAMESPACES = Arrays.asList(NAMESPACE_1,
+ NAMESPACE_2, NAMESPACE_3);
+
+ private static final String PACKAGE_1 = "com.android.test1";
+ private static final String PACKAGE_2 = "com.android.test2";
+ private static final String PACKAGE_3 = "com.android.test3";
+ private static final String PACKAGE_4 = "com.android.test4";
+ private static final String PACKAGE_5 = "com.android.test5";
+
+ private MockContext mMockContext;
+ private BroadcastReceiver mPackageReceiver;
+ private AppCompatOverridesService mService;
+
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private IPlatformCompat mPlatformCompat;
+
+ @Captor
+ private ArgumentCaptor<CompatibilityOverrideConfig> mOverridesToAddConfigCaptor;
+ @Captor
+ private ArgumentCaptor<CompatibilityOverridesToRemoveConfig> mOverridesToRemoveConfigCaptor;
+
+ @Rule
+ public TestableDeviceConfigRule mDeviceConfigRule = new TestableDeviceConfigRule();
+
+ class MockContext extends ContextWrapper {
+ MockContext(Context base) {
+ super(base);
+ }
+
+ @Override
+ public PackageManager getPackageManager() {
+ return mPackageManager;
+ }
+
+ @Override
+ public Executor getMainExecutor() {
+ // Run on current thread
+ return Runnable::run;
+ }
+
+ @Override
+ @Nullable
+ public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
+ @NonNull IntentFilter filter, @Nullable String broadcastPermission,
+ @Nullable Handler scheduler) {
+ mPackageReceiver = receiver;
+ return null;
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mMockContext = new MockContext(
+ InstrumentationRegistry.getInstrumentation().getTargetContext());
+ mService = new AppCompatOverridesService(mMockContext, mPlatformCompat,
+ SUPPORTED_NAMESPACES);
+ mService.registerPackageReceiver();
+ assertThat(mPackageReceiver).isNotNull();
+ }
+
+ @Test
+ public void onPropertiesChanged_removeOverridesFlagNotSet_appliesPackageOverrides()
+ throws Exception {
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 3);
+ mockGetApplicationInfoNotInstalled(PACKAGE_2);
+ mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 10);
+ mockGetApplicationInfo(PACKAGE_4, /* versionCode= */ 1);
+ mockGetApplicationInfo(PACKAGE_5, /* versionCode= */ 1);
+
+ mService.registerDeviceConfigListeners();
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(PACKAGE_1, "123:::true,456::1:false,456:2::true")
+ .setString(PACKAGE_2, "123:::true")
+ .setString(PACKAGE_3, "123:1:9:true,123:10:11:false,123:11::true,456:::")
+ .setString(PACKAGE_4, "")
+ .setString(PACKAGE_5, "123:::,789:::")
+ .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789").build());
+
+ Map<Long, PackageOverride> addedOverrides;
+ // Package 1
+ verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
+ eq(PACKAGE_1));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+ addedOverrides = mOverridesToAddConfigCaptor.getValue().overrides;
+ assertThat(addedOverrides).hasSize(2);
+ assertThat(addedOverrides.get(123L)).isEqualTo(
+ new PackageOverride.Builder().setEnabled(true).build());
+ assertThat(addedOverrides.get(456L)).isEqualTo(
+ new PackageOverride.Builder().setMinVersionCode(2).setEnabled(true).build());
+ // Package 2
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2));
+ // Package 3
+ verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
+ eq(PACKAGE_3));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_3));
+ addedOverrides = mOverridesToAddConfigCaptor.getValue().overrides;
+ assertThat(addedOverrides).hasSize(1);
+ assertThat(addedOverrides.get(123L)).isEqualTo(
+ new PackageOverride.Builder().setMinVersionCode(10).setMaxVersionCode(
+ 11).setEnabled(false).build());
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L);
+ // Package 4
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_4));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4));
+ // Package 5
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_5));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_5));
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 789L);
+ }
+
+ @Test
+ public void onPropertiesChanged_removeOverridesFlagSetBefore_skipsOverridesToRemove()
+ throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=123:456," + PACKAGE_2 + "=123")
+ .setString(PACKAGE_1, "123:::true")
+ .setString(PACKAGE_4, "123:::true").build());
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+ mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0);
+ mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 0);
+
+ mService.registerDeviceConfigListeners();
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(PACKAGE_1, "123:::true,456:::,789:::false")
+ .setString(PACKAGE_2, "123:::true")
+ .setString(PACKAGE_3, "456:::true").build());
+
+ // Package 1
+ verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
+ eq(PACKAGE_1));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+ assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(789L);
+ // Package 2
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2));
+ // Package 3
+ verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
+ eq(PACKAGE_3));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3));
+ assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(456L);
+ // Package 4 (not applied because it hasn't changed after the listener was added)
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_4));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4));
+ }
+
+ @Test
+ public void onPropertiesChanged_removeOverridesFlagChangedNoPackageOverridesFlags_removesOnly()
+ throws Exception {
+ mService.registerDeviceConfigListeners();
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_REMOVE_OVERRIDES,
+ PACKAGE_1 + "=123:456," + PACKAGE_2 + "=789").build());
+
+ // Package 1
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L);
+ // Package 2
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(789L);
+ }
+
+ @Test
+ public void onPropertiesChanged_removeOverridesFlagAndSomePackageOverrideFlagsChanged_ok()
+ throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=123:456")
+ .setString(PACKAGE_1, "123:::true,456:::,789:::false")
+ .setString(PACKAGE_3, "456:::false,789:::true").build());
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+ mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0);
+ mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 0);
+
+ mService.registerDeviceConfigListeners();
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_2 + "=123," + PACKAGE_3 + "=789")
+ .setString(PACKAGE_2, "123:::true,456:::").build());
+
+ // Package 1
+ verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
+ eq(PACKAGE_1));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
+ assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(123L,
+ 789L);
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L);
+ // Package 2
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
+ verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
+ List<CompatibilityOverridesToRemoveConfig> configs =
+ mOverridesToRemoveConfigCaptor.getAllValues();
+ assertThat(configs.size()).isAtLeast(2);
+ assertThat(configs.get(configs.size() - 2).changeIds).containsExactly(123L);
+ assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(456L);
+ // Package 3
+ verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
+ eq(PACKAGE_3));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_3));
+ assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(456L);
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(789L);
+ }
+
+ @Test
+ public void onPropertiesChanged_ownedChangeIdsFlagAndSomePackageOverrideFlagsChanged_ok()
+ throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=*")
+ .setString(FLAG_OWNED_CHANGE_IDS, "123,456")
+ .setString(PACKAGE_1, "123:::true")
+ .setString(PACKAGE_3, "456:::false").build());
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+ mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0);
+ mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 0);
+
+ mService.registerDeviceConfigListeners();
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789")
+ .setString(PACKAGE_2, "123:::true").build());
+
+ // Package 1
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L,
+ 789L);
+ // Package 2
+ verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
+ eq(PACKAGE_2));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2));
+ assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(123L);
+ // Package 3
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_3));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3));
+ }
+
+ @Test
+ public void onPropertiesChanged_platformCompatThrowsExceptionForSomeCalls_skipsFailedCalls()
+ throws Exception {
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+ mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0);
+ mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 0);
+ mockGetApplicationInfo(PACKAGE_4, /* versionCode= */ 0);
+ doThrow(new RemoteException()).when(mPlatformCompat).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
+ doThrow(new RemoteException()).when(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3));
+
+ mService.registerDeviceConfigListeners();
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(PACKAGE_1, "123:::true,456:::")
+ .setString(PACKAGE_2, "123:::true,456:::")
+ .setString(PACKAGE_3, "123:::true,456:::")
+ .setString(PACKAGE_4, "123:::true,456:::").build());
+
+ // Package 1
+ verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class),
+ eq(PACKAGE_1));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+ // Package 2
+ verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class),
+ eq(PACKAGE_2));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2));
+ // Package 3
+ verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class),
+ eq(PACKAGE_3));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3));
+ // Package 4
+ verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class),
+ eq(PACKAGE_1));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4));
+ }
+
+ @Test
+ public void packageReceiver_packageAddedIntentDataIsNull_doesNothing() throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(PACKAGE_1, "101:::true").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
+ .setString(PACKAGE_1, "201:::true").build());
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+
+ mPackageReceiver.onReceive(mMockContext, new Intent(ACTION_PACKAGE_ADDED));
+
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+ }
+
+ @Test
+ public void packageReceiver_actionIsNull_doesNothing() throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(PACKAGE_1, "101:::true").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
+ .setString(PACKAGE_1, "201:::true").build());
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+
+ mPackageReceiver.onReceive(mMockContext,
+ createPackageIntent(PACKAGE_1, /* action= */ null));
+
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+ }
+
+ @Test
+ public void packageReceiver_unsupportedAction_doesNothing() throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(PACKAGE_1, "101:::true").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
+ .setString(PACKAGE_1, "201:::true").build());
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+
+ mPackageReceiver.onReceive(mMockContext,
+ createPackageIntent(PACKAGE_1, ACTION_USER_SWITCHED));
+
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+ }
+
+ @Test
+ public void packageReceiver_packageAddedIntentPackageNotInstalled_doesNothing()
+ throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(PACKAGE_1, "101:::true").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
+ .setString(PACKAGE_1, "201:::true").build());
+ mockGetApplicationInfoNotInstalled(PACKAGE_1);
+
+ mPackageReceiver.onReceive(mMockContext,
+ createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
+
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+ }
+
+ @Test
+ public void packageReceiver_packageAddedIntentNoOverridesForPackage_doesNothing()
+ throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(PACKAGE_2, "101:::true").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
+ .setString(PACKAGE_3, "201:::true").build());
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+
+ mPackageReceiver.onReceive(mMockContext,
+ createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
+
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+ }
+
+ @Test
+ public void packageReceiver_packageAddedIntent_appliesOverridesFromAllNamespaces()
+ throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(PACKAGE_1, "101:::true,103:::")
+ .setString(PACKAGE_2, "102:::false").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
+ .setString(PACKAGE_3, "201:::false").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
+ .setString(PACKAGE_1, "301:::true,302:::false")
+ .setString(PACKAGE_2, "302:::false").build());
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+
+ mPackageReceiver.onReceive(mMockContext,
+ createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
+
+ verify(mPlatformCompat, times(2)).putOverridesOnReleaseBuilds(
+ mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
+ List<CompatibilityOverrideConfig> configs = mOverridesToAddConfigCaptor.getAllValues();
+ assertThat(configs.get(0).overrides.keySet()).containsExactly(101L);
+ assertThat(configs.get(1).overrides.keySet()).containsExactly(301L, 302L);
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(103L);
+ }
+
+ @Test
+ public void packageReceiver_packageChangedIntent_appliesOverrides()
+ throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(PACKAGE_1, "101:::true,103:::").build());
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+
+ mPackageReceiver.onReceive(mMockContext,
+ createPackageIntent(PACKAGE_1, ACTION_PACKAGE_CHANGED));
+
+ verify(mPlatformCompat).putOverridesOnReleaseBuilds(
+ mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
+ assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(101L);
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(103L);
+ }
+
+ @Test
+ public void packageReceiver_packageAddedIntentRemoveOverridesSetForSomeNamespaces_skipsIds()
+ throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=103," + PACKAGE_2 + "=101")
+ .setString(PACKAGE_1, "101:::true,103:::")
+ .setString(PACKAGE_2, "102:::false").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
+ .setString(PACKAGE_1, "201:::false").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
+ .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=301," + PACKAGE_3 + "=302")
+ .setString(PACKAGE_1, "301:::true,302:::false,303:::")
+ .setString(PACKAGE_3, "302:::false").build());
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+
+ mPackageReceiver.onReceive(mMockContext,
+ createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
+
+ verify(mPlatformCompat, times(3)).putOverridesOnReleaseBuilds(
+ mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
+ List<CompatibilityOverrideConfig> configs = mOverridesToAddConfigCaptor.getAllValues();
+ assertThat(configs.get(0).overrides.keySet()).containsExactly(101L);
+ assertThat(configs.get(1).overrides.keySet()).containsExactly(201L);
+ assertThat(configs.get(2).overrides.keySet()).containsExactly(302L);
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(303L);
+ }
+
+ @Test
+ public void packageReceiver_packageRemovedIntentNoOverridesForPackage_doesNothing()
+ throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_OWNED_CHANGE_IDS, "101,102")
+ .setString(PACKAGE_2, "101:::true").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
+ .setString(FLAG_OWNED_CHANGE_IDS, "201,202")
+ .setString(PACKAGE_3, "201:::true").build());
+ mockGetApplicationInfoNotInstalled(PACKAGE_1);
+
+ mPackageReceiver.onReceive(mMockContext,
+ createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED));
+
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+ }
+
+ @Test
+ public void packageReceiver_packageRemovedIntentPackageInstalledForAnotherUser_doesNothing()
+ throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_OWNED_CHANGE_IDS, "101,102,103")
+ .setString(PACKAGE_1, "101:::true,103:::").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
+ .setString(FLAG_OWNED_CHANGE_IDS, "201,202")
+ .setString(PACKAGE_1, "202:::false").build());
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+
+ mPackageReceiver.onReceive(mMockContext,
+ createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED));
+
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+ }
+
+ @Test
+ public void packageReceiver_packageRemovedIntent_removesOwnedOverridesForNamespacesWithPackage()
+ throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_OWNED_CHANGE_IDS, "101,102,103")
+ .setString(PACKAGE_1, "101:::true,103:::")
+ .setString(PACKAGE_2, "102:::false").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
+ .setString(FLAG_OWNED_CHANGE_IDS, "201")
+ .setString(PACKAGE_3, "201:::false").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
+ .setString(FLAG_OWNED_CHANGE_IDS, "301,302")
+ .setString(PACKAGE_1, "302:::")
+ .setString(PACKAGE_2, "301:::true").build());
+ mockGetApplicationInfoNotInstalled(PACKAGE_1);
+
+ mPackageReceiver.onReceive(mMockContext,
+ createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED));
+
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
+ verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
+ List<CompatibilityOverridesToRemoveConfig> configs =
+ mOverridesToRemoveConfigCaptor.getAllValues();
+ assertThat(configs.get(0).changeIds).containsExactly(101L, 102L, 103L);
+ assertThat(configs.get(1).changeIds).containsExactly(301L, 302L);
+ }
+
+ @Test
+ public void packageReceiver_packageRemovedIntentNoOwnedIdsForSomeNamespace_skipsNamespace()
+ throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_OWNED_CHANGE_IDS, "101,102")
+ .setString(PACKAGE_1, "101:::true").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
+ .setString(PACKAGE_1, "201:::false").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
+ .setString(FLAG_OWNED_CHANGE_IDS, "301")
+ .setString(PACKAGE_1, "301:::true").build());
+ mockGetApplicationInfoNotInstalled(PACKAGE_1);
+
+ mPackageReceiver.onReceive(mMockContext,
+ createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED));
+
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
+ verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
+ List<CompatibilityOverridesToRemoveConfig> configs =
+ mOverridesToRemoveConfigCaptor.getAllValues();
+ assertThat(configs.get(0).changeIds).containsExactly(101L, 102L);
+ assertThat(configs.get(1).changeIds).containsExactly(301L);
+ }
+
+ @Test
+ public void packageReceiver_platformCompatThrowsExceptionForSomeNamespace_skipsFailedCall()
+ throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(PACKAGE_1, "101:::true").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
+ .setString(PACKAGE_1, "201:::false").build());
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
+ .setString(PACKAGE_1, "301:::true").build());
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+ doThrow(new RemoteException()).when(mPlatformCompat).putOverridesOnReleaseBuilds(
+ argThat(config -> config.overrides.containsKey(201L)), eq(PACKAGE_1));
+
+ mPackageReceiver.onReceive(mMockContext,
+ createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
+
+ verify(mPlatformCompat, times(3)).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+ }
+
+ private void mockGetApplicationInfo(String packageName, long versionCode)
+ throws Exception {
+ when(mPackageManager.getApplicationInfo(eq(packageName), anyInt())).thenReturn(
+ createAppInfo(versionCode));
+ }
+
+ private void mockGetApplicationInfoNotInstalled(String packageName) throws Exception {
+ when(mPackageManager.getApplicationInfo(eq(packageName), anyInt()))
+ .thenThrow(new PackageManager.NameNotFoundException());
+ }
+
+ private static ApplicationInfo createAppInfo(long versionCode) {
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.longVersionCode = versionCode;
+ return appInfo;
+ }
+
+ private Intent createPackageIntent(String packageName, @Nullable String action) {
+ return new Intent(action, Uri.parse("package:" + packageName));
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index c407429..a9853bf 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -152,6 +152,11 @@
.setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1),
DataUnit.MEBIBYTES.toBytes(1))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ final JobInfo.Builder jobWithMinChunk = createJob()
+ .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1),
+ DataUnit.MEBIBYTES.toBytes(1))
+ .setMinimumNetworkChunkBytes(DataUnit.KIBIBYTES.toBytes(100))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
final ArgumentCaptor<BroadcastReceiver> chargingCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
@@ -170,18 +175,51 @@
assertFalse(controller.isSatisfied(createJobStatus(job), net,
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(1)
.setLinkDownstreamBandwidthKbps(1).build(), mConstants));
+ assertFalse(controller.isSatisfied(createJobStatus(jobWithMinChunk), net,
+ createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(1)
+ .setLinkDownstreamBandwidthKbps(1).build(), mConstants));
// Slow downstream
assertFalse(controller.isSatisfied(createJobStatus(job), net,
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(1024)
.setLinkDownstreamBandwidthKbps(1).build(), mConstants));
+ assertFalse(controller.isSatisfied(createJobStatus(jobWithMinChunk), net,
+ createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(1024)
+ .setLinkDownstreamBandwidthKbps(1).build(), mConstants));
// Slow upstream
assertFalse(controller.isSatisfied(createJobStatus(job), net,
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(1)
.setLinkDownstreamBandwidthKbps(1024).build(), mConstants));
+ assertFalse(controller.isSatisfied(createJobStatus(jobWithMinChunk), net,
+ createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(1)
+ .setLinkDownstreamBandwidthKbps(1024).build(), mConstants));
+ // Medium network is fine for min chunk
+ assertFalse(controller.isSatisfied(createJobStatus(job), net,
+ createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(5)
+ .setLinkDownstreamBandwidthKbps(5).build(), mConstants));
+ assertTrue(controller.isSatisfied(createJobStatus(jobWithMinChunk), net,
+ createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(5)
+ .setLinkDownstreamBandwidthKbps(5).build(), mConstants));
+ // Medium downstream
+ assertFalse(controller.isSatisfied(createJobStatus(job), net,
+ createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(1024)
+ .setLinkDownstreamBandwidthKbps(5).build(), mConstants));
+ assertTrue(controller.isSatisfied(createJobStatus(jobWithMinChunk), net,
+ createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(1024)
+ .setLinkDownstreamBandwidthKbps(5).build(), mConstants));
+ // Medium upstream
+ assertFalse(controller.isSatisfied(createJobStatus(job), net,
+ createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(5)
+ .setLinkDownstreamBandwidthKbps(1024).build(), mConstants));
+ assertTrue(controller.isSatisfied(createJobStatus(jobWithMinChunk), net,
+ createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(5)
+ .setLinkDownstreamBandwidthKbps(1024).build(), mConstants));
// Fast network looks great
assertTrue(controller.isSatisfied(createJobStatus(job), net,
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(1024)
.setLinkDownstreamBandwidthKbps(1024).build(), mConstants));
+ assertTrue(controller.isSatisfied(createJobStatus(jobWithMinChunk), net,
+ createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(1024)
+ .setLinkDownstreamBandwidthKbps(1024).build(), mConstants));
// Slow network still good given time
assertTrue(controller.isSatisfied(createJobStatus(job), net,
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(130)
@@ -241,7 +279,6 @@
final ConnectivityController controller = new ConnectivityController(mService);
when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(10 * 60_000L);
-
// Suspended networks aren't usable.
assertFalse(controller.isSatisfied(createJobStatus(job), net,
createCapabilitiesBuilder().removeCapability(NET_CAPABILITY_NOT_SUSPENDED)
diff --git a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java
index 43188f6..60a7f78 100644
--- a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java
+++ b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java
@@ -101,6 +101,15 @@
).when(() -> DeviceConfig.setProperty(anyString(), anyString(), anyString(), anyBoolean()));
doAnswer((Answer<Boolean>) invocationOnMock -> {
+ String namespace = invocationOnMock.getArgument(0);
+ String name = invocationOnMock.getArgument(1);
+ mKeyValueMap.remove(getKey(namespace, name));
+ invokeListeners(namespace, getProperties(namespace, name, null));
+ return true;
+ }
+ ).when(() -> DeviceConfig.deleteProperty(anyString(), anyString()));
+
+ doAnswer((Answer<Boolean>) invocationOnMock -> {
Properties properties = invocationOnMock.getArgument(0);
String namespace = properties.getNamespace();
Map<String, String> keyValues = new ArrayMap<>();
diff --git a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfigTest.java b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfigTest.java
index d68b814..f9f4387 100644
--- a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfigTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfigTest.java
@@ -103,6 +103,20 @@
}
@Test
+ public void deleteProperty() {
+ DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
+ assertThat(DeviceConfig.getProperty(sNamespace, sKey)).isEqualTo(sValue);
+ DeviceConfig.deleteProperty(sNamespace, sKey);
+ assertThat(DeviceConfig.getProperty(sNamespace, sKey)).isNull();
+ String newNamespace = "namespace2";
+ String newValue = "value2";
+ DeviceConfig.setProperty(newNamespace, sKey, newValue, false);
+ assertThat(DeviceConfig.getProperty(newNamespace, sKey)).isEqualTo(newValue);
+ DeviceConfig.deleteProperty(newNamespace, sKey);
+ assertThat(DeviceConfig.getProperty(newNamespace, sKey)).isNull();
+ }
+
+ @Test
public void getProperties_empty() {
String newKey = "key2";
String newValue = "value2";
@@ -189,6 +203,27 @@
}
}
+ @Test
+ public void testListener_deleteProperty() throws InterruptedException {
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+
+ OnPropertiesChangedListener changeListener = (properties) -> {
+ assertThat(properties.getNamespace()).isEqualTo(sNamespace);
+ assertThat(properties.getKeyset()).containsExactly(sKey);
+ assertThat(properties.getString(sKey, "bogus_value")).isEqualTo("bogus_value");
+ assertThat(properties.getString("bogus_key", "bogus_value")).isEqualTo("bogus_value");
+ countDownLatch.countDown();
+ };
+ try {
+ DeviceConfig.addOnPropertiesChangedListener(sNamespace,
+ ActivityThread.currentApplication().getMainExecutor(), changeListener);
+ DeviceConfig.deleteProperty(sNamespace, sKey);
+ assertThat(countDownLatch.await(
+ WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
+ } finally {
+ DeviceConfig.removeOnPropertiesChangedListener(changeListener);
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index fb768a8..8b8a7e6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -37,6 +37,7 @@
import android.apex.ApexSessionParams;
import android.apex.IApexService;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -349,9 +350,9 @@
}
@Test
- public void testInstallPackage() throws Exception {
+ public void testInstallPackage_activeOnSystem() throws Exception {
ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,
- /* isFactory= */ false, extractResource("test.apex_rebootless_v1",
+ /* isFactory= */ true, extractResource("test.apex_rebootless_v1",
"test.rebootless_apex_v1.apex"));
when(mApexService.getAllPackages()).thenReturn(new ApexInfo[]{activeApexInfo});
mApexManager.scanApexPackagesTraced(mPackageParser2,
@@ -369,6 +370,55 @@
ApexManager.MATCH_ACTIVE_PACKAGE);
assertThat(newInfo.applicationInfo.sourceDir).isEqualTo(finalApex.getAbsolutePath());
assertThat(newInfo.applicationInfo.longVersionCode).isEqualTo(2);
+ assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0);
+ assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
+ .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
+
+ PackageInfo factoryInfo = mApexManager.getPackageInfo("test.apex.rebootless",
+ ApexManager.MATCH_FACTORY_PACKAGE);
+ assertThat(factoryInfo.applicationInfo.sourceDir).isEqualTo(activeApexInfo.modulePath);
+ assertThat(factoryInfo.applicationInfo.longVersionCode).isEqualTo(1);
+ assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
+ assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
+ }
+
+ @Test
+ public void testInstallPackage_activeOnData() throws Exception {
+ ApexInfo factoryApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ false,
+ /* isFactory= */ true, extractResource("test.apex_rebootless_v1",
+ "test.rebootless_apex_v1.apex"));
+ ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,
+ /* isFactory= */ false, extractResource("test.apex.rebootless@1",
+ "test.rebootless_apex_v1.apex"));
+ when(mApexService.getAllPackages())
+ .thenReturn(new ApexInfo[]{factoryApexInfo, activeApexInfo});
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
+
+ File finalApex = extractResource("test.rebootles_apex_v2", "test.rebootless_apex_v2.apex");
+ ApexInfo newApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true,
+ /* isFactory= */ false, finalApex);
+ when(mApexService.installAndActivatePackage(anyString())).thenReturn(newApexInfo);
+
+ File installedApex = extractResource("installed", "test.rebootless_apex_v2.apex");
+ mApexManager.installPackage(installedApex, mPackageParser2);
+
+ PackageInfo newInfo = mApexManager.getPackageInfo("test.apex.rebootless",
+ ApexManager.MATCH_ACTIVE_PACKAGE);
+ assertThat(newInfo.applicationInfo.sourceDir).isEqualTo(finalApex.getAbsolutePath());
+ assertThat(newInfo.applicationInfo.longVersionCode).isEqualTo(2);
+ assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0);
+ assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
+ .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
+
+ PackageInfo factoryInfo = mApexManager.getPackageInfo("test.apex.rebootless",
+ ApexManager.MATCH_FACTORY_PACKAGE);
+ assertThat(factoryInfo.applicationInfo.sourceDir).isEqualTo(factoryApexInfo.modulePath);
+ assertThat(factoryInfo.applicationInfo.longVersionCode).isEqualTo(1);
+ assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
+ assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 29f4aa9..22fb76b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -198,6 +198,7 @@
new WatchableTester(settingsUnderTest, "noSuspendingPackage");
watcher.register();
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+ settingsUnderTest.readPackageRestrictionsLPr(0);
watcher.verifyChangeReported("put package 1");
// Collect a snapshot at the midway point (package 2 has not been added)
final Settings snapshot = settingsUnderTest.snapshot();
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
index a0e9d97..0363625 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
@@ -15,6 +15,7 @@
*/
package com.android.server.timezonedetector.location;
+import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_INITIALIZING;
@@ -728,6 +729,9 @@
// Simulate the user change (but geo detection still enabled).
testEnvironment.simulateConfigChange(USER2_CONFIG_GEO_DETECTION_ENABLED);
+ // Confirm that the previous suggestion was overridden.
+ mTestCallback.assertUncertainSuggestionMadeAndCommit();
+
// We expect the provider to end up in PROVIDER_STATE_STARTED_INITIALIZING, but it should
// have been stopped when the user changed.
int[] expectedStateTransitions =
@@ -1068,6 +1072,48 @@
}
}
+ @Test
+ public void destroy() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+ TestEnvironment testEnvironment = new TestEnvironment(
+ mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
+ controllerImpl.initialize(testEnvironment, mTestCallback);
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+ mTestCallback.assertNoSuggestionMade();
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Simulate the primary provider suggesting a time zone.
+ mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
+
+ // Receiving a "success" provider event should cause a suggestion to be made synchronously,
+ // and also clear the scheduled uncertainty suggestion.
+ mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+ PROVIDER_STATE_STARTED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
+ mTestSecondaryLocationTimeZoneProvider.assertIsStoppedAndCommit();
+ mTestCallback.assertSuggestionMadeAndCommit(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds());
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+
+ // Trigger destroy().
+ controllerImpl.destroy();
+
+ // Confirm that the previous suggestion was overridden.
+ mTestCallback.assertUncertainSuggestionMadeAndCommit();
+
+ mTestPrimaryLocationTimeZoneProvider.assertStateChangesAndCommit(
+ PROVIDER_STATE_STOPPED, PROVIDER_STATE_DESTROYED);
+ mTestSecondaryLocationTimeZoneProvider.assertStateChangesAndCommit(
+ PROVIDER_STATE_DESTROYED);
+ assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+ }
+
private static void assertUncertaintyTimeoutSet(
LocationTimeZoneProviderController.Environment environment,
LocationTimeZoneProviderController controller) {
@@ -1175,7 +1221,6 @@
private final TestState<ProviderState> mTestProviderState = new TestState<>();
private boolean mFailDuringInitialization;
private boolean mInitialized;
- private boolean mDestroyed;
/**
* Creates the instance.
@@ -1200,7 +1245,7 @@
@Override
void onDestroy() {
- mDestroyed = true;
+ // No behavior needed.
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
index 1596483..2e5c24c 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -246,6 +246,81 @@
}
@Test
+ public void vibrate_singleVibratorRepeatingShortAlwaysOnWaveform_turnsVibratorOnForASecond()
+ throws Exception {
+ FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
+ fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+
+ long vibrationId = 1;
+ int[] amplitudes = new int[]{1, 2, 3};
+ VibrationEffect effect = VibrationEffect.createWaveform(
+ new long[]{1, 10, 100}, amplitudes, 0);
+ VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+
+ assertTrue(waitUntil(t -> !fakeVibrator.getAmplitudes().isEmpty(), thread,
+ TEST_TIMEOUT_MILLIS));
+ thread.cancel();
+ waitForCompletion(thread);
+
+ verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+ assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertEquals(Arrays.asList(expectedOneShot(1000)), fakeVibrator.getEffectSegments());
+ }
+
+ @Test
+ public void vibrate_singleVibratorRepeatingLongAlwaysOnWaveform_turnsVibratorOnForACycle()
+ throws Exception {
+ FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
+ fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+
+ long vibrationId = 1;
+ int[] amplitudes = new int[]{1, 2, 3};
+ VibrationEffect effect = VibrationEffect.createWaveform(
+ new long[]{5000, 500, 50}, amplitudes, 0);
+ VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+
+ assertTrue(waitUntil(t -> !fakeVibrator.getAmplitudes().isEmpty(), thread,
+ TEST_TIMEOUT_MILLIS));
+ thread.cancel();
+ waitForCompletion(thread);
+
+ verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+ assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertEquals(Arrays.asList(expectedOneShot(5550)), fakeVibrator.getEffectSegments());
+ }
+
+
+ @Test
+ public void vibrate_singleVibratorRepeatingAlwaysOnWaveform_turnsVibratorBackOn()
+ throws Exception {
+ FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
+ fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+
+ long vibrationId = 1;
+ int[] amplitudes = new int[]{1, 2};
+ VibrationEffect effect = VibrationEffect.createWaveform(
+ new long[]{900, 50}, amplitudes, 0);
+ VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+
+ assertTrue(waitUntil(t -> fakeVibrator.getAmplitudes().size() > 2 * amplitudes.length,
+ thread, 1000 + TEST_TIMEOUT_MILLIS));
+ thread.cancel();
+ waitForCompletion(thread);
+
+ verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+ assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertEquals(2, fakeVibrator.getEffectSegments().size());
+ // First time turn vibrator ON for minimum of 1s.
+ assertEquals(1000L, fakeVibrator.getEffectSegments().get(0).getDuration());
+ // Vibrator turns off in the middle of the second execution of first step, turn it back ON
+ // for another 1s + remaining of 850ms.
+ assertEquals(1850, fakeVibrator.getEffectSegments().get(1).getDuration(), /* delta= */ 20);
+ // Set amplitudes for a cycle {1, 2}, start second loop then turn it back on to same value.
+ assertEquals(expectedAmplitudes(1, 2, 1, 1),
+ mVibratorProviders.get(VIBRATOR_ID).getAmplitudes().subList(0, 4));
+ }
+
+ @Test
public void vibrate_singleVibratorPredefinedCancel_cancelsVibrationImmediately()
throws Exception {
mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index d0bf63a..733d3f0 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -281,6 +281,34 @@
assertNull(fromXml.pkg);
}
+ @Test
+ public void testRuleXml_getPkg_nullPkg() throws Exception {
+ String tag = "tag";
+
+ ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
+ rule.enabled = true;
+ rule.configurationActivity = new ComponentName("a", "a");
+
+ TypedXmlSerializer out = Xml.newFastSerializer();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ out.setOutput(new BufferedOutputStream(baos), "utf-8");
+ out.startDocument(null, true);
+ out.startTag(null, tag);
+ ZenModeConfig.writeRuleXml(rule, out);
+ out.endTag(null, tag);
+ out.endDocument();
+
+ TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ ZenModeConfig.ZenRule fromXml = ZenModeConfig.readRuleXml(parser);
+ assertEquals("a", fromXml.getPkg());
+
+ fromXml.condition = new Condition(Uri.EMPTY, "", Condition.STATE_TRUE);
+ assertTrue(fromXml.isAutomaticActive());
+ }
+
private ZenModeConfig getMutedRingerConfig() {
ZenModeConfig config = new ZenModeConfig();
// Allow alarms, media
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 00dbaf6..4410404 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -33,6 +33,7 @@
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+import static android.service.notification.Condition.STATE_TRUE;
import static android.util.StatsLog.ANNOTATION_ID_IS_UID;
import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
@@ -49,6 +50,7 @@
import static junit.framework.TestCase.fail;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -64,6 +66,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AutomaticZenRule;
@@ -72,7 +76,9 @@
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.media.AudioAttributes;
@@ -81,6 +87,7 @@
import android.media.AudioSystem;
import android.media.VolumePolicy;
import android.net.Uri;
+import android.os.Binder;
import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
@@ -105,6 +112,8 @@
import com.android.server.UiServiceTestCase;
import com.android.server.notification.ManagedServices.UserProfiles;
+import com.google.common.collect.ImmutableList;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -172,8 +181,14 @@
mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(),
mConditionProviders, mStatsEventBuilderFactory));
+ ResolveInfo ri = new ResolveInfo();
+ ri.activityInfo = new ActivityInfo();
+ when(mPackageManager.queryIntentActivitiesAsUser(any(), anyInt(), anyInt())).thenReturn(
+ ImmutableList.of(ri));
when(mPackageManager.getPackageUidAsUser(eq(CUSTOM_PKG_NAME), anyInt()))
.thenReturn(CUSTOM_PKG_UID);
+ when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(
+ new String[] {getContext().getPackageName()});
mZenModeHelperSpy.mPm = mPackageManager;
}
@@ -1486,7 +1501,7 @@
mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("android",
CountdownConditionProvider.class.getName());
mZenModeHelperSpy.mConfig.manualRule.condition = new Condition(conditionId, "", "", "", 0,
- Condition.STATE_TRUE, Condition.FLAG_RELEVANT_NOW);
+ STATE_TRUE, Condition.FLAG_RELEVANT_NOW);
mZenModeHelperSpy.mConfig.manualRule.enabled = true;
ZenModeConfig originalConfig = mZenModeHelperSpy.mConfig.copy();
@@ -1592,7 +1607,29 @@
}
@Test
- public void testAddAutomaticZenRule() {
+ public void testAddAutomaticZenRule_CA() {
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ null,
+ new ComponentName("android", "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test");
+
+ assertTrue(id != null);
+ ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id);
+ assertTrue(ruleInConfig != null);
+ assertEquals(zenRule.isEnabled(), ruleInConfig.enabled);
+ assertEquals(zenRule.isModified(), ruleInConfig.modified);
+ assertEquals(zenRule.getConditionId(), ruleInConfig.conditionId);
+ assertEquals(NotificationManager.zenModeFromInterruptionFilter(
+ zenRule.getInterruptionFilter(), -1), ruleInConfig.zenMode);
+ assertEquals(zenRule.getName(), ruleInConfig.name);
+ assertEquals("android", ruleInConfig.pkg);
+ }
+
+ @Test
+ public void testAddAutomaticZenRule_CPS() {
AutomaticZenRule zenRule = new AutomaticZenRule("name",
new ComponentName("android", "ScheduleConditionProvider"),
ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
@@ -1608,6 +1645,87 @@
assertEquals(NotificationManager.zenModeFromInterruptionFilter(
zenRule.getInterruptionFilter(), -1), ruleInConfig.zenMode);
assertEquals(zenRule.getName(), ruleInConfig.name);
+ assertEquals("android", ruleInConfig.pkg);
+ }
+
+ @Test
+ public void testSetAutomaticZenRuleState_nullPkg() {
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ null,
+ new ComponentName(mContext.getPackageName(), "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+
+ String id = mZenModeHelperSpy.addAutomaticZenRule(null, zenRule, "test");
+ mZenModeHelperSpy.setAutomaticZenRuleState(zenRule.getConditionId(),
+ new Condition(zenRule.getConditionId(), "", STATE_TRUE));
+
+ ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id);
+ assertEquals(STATE_TRUE, ruleInConfig.condition.state);
+ }
+
+ @Test
+ public void testUpdateAutomaticZenRule_nullPkg() {
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ null,
+ new ComponentName(mContext.getPackageName(), "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+
+ String id = mZenModeHelperSpy.addAutomaticZenRule(null, zenRule, "test");
+
+ AutomaticZenRule zenRule2 = new AutomaticZenRule("NEW",
+ null,
+ new ComponentName(mContext.getPackageName(), "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+
+ mZenModeHelperSpy.updateAutomaticZenRule(id, zenRule2, "");
+
+ ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id);
+ assertEquals("NEW", ruleInConfig.name);
+ }
+
+ @Test
+ public void testRemoveAutomaticZenRule_nullPkg() {
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ null,
+ new ComponentName(mContext.getPackageName(), "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+
+ String id = mZenModeHelperSpy.addAutomaticZenRule(null, zenRule, "test");
+
+ assertTrue(id != null);
+ ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id);
+ assertTrue(ruleInConfig != null);
+ assertEquals(zenRule.getName(), ruleInConfig.name);
+
+ mZenModeHelperSpy.removeAutomaticZenRule(id, "test");
+ assertNull(mZenModeHelperSpy.mConfig.automaticRules.get(id));
+ }
+
+ @Test
+ public void testRemoveAutomaticZenRules_nullPkg() {
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ null,
+ new ComponentName(mContext.getPackageName(), "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule(null, zenRule, "test");
+
+ assertTrue(id != null);
+ ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id);
+ assertTrue(ruleInConfig != null);
+ assertEquals(zenRule.getName(), ruleInConfig.name);
+
+ mZenModeHelperSpy.removeAutomaticZenRules(mContext.getPackageName(), "test");
+ assertNull(mZenModeHelperSpy.mConfig.automaticRules.get(id));
}
@Test
@@ -1624,17 +1742,17 @@
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id2 = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule2, "test");
- Condition condition = new Condition(sharedUri, "", Condition.STATE_TRUE);
+ Condition condition = new Condition(sharedUri, "", STATE_TRUE);
mZenModeHelperSpy.setAutomaticZenRuleState(sharedUri, condition);
for (ZenModeConfig.ZenRule rule : mZenModeHelperSpy.mConfig.automaticRules.values()) {
if (rule.id.equals(id)) {
assertNotNull(rule.condition);
- assertTrue(rule.condition.state == Condition.STATE_TRUE);
+ assertTrue(rule.condition.state == STATE_TRUE);
}
if (rule.id.equals(id2)) {
assertNotNull(rule.condition);
- assertTrue(rule.condition.state == Condition.STATE_TRUE);
+ assertTrue(rule.condition.state == STATE_TRUE);
}
}
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 d0588a3..2df9a8d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -1136,6 +1136,7 @@
/* doResume */true,
/* options */null,
/* inTask */null,
+ /* inTaskFragment */ null,
/* restrictedBgActivity */false,
/* intentGrants */null);
@@ -1146,6 +1147,31 @@
}
@Test
+ public void testStartActivityInner_inTaskFragment() {
+ final ActivityStarter starter = prepareStarter(0, false);
+ final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
+ final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token,
+ true /* createdByOrganizer */);
+ sourceRecord.getTask().addChild(taskFragment, POSITION_TOP);
+
+ starter.startActivityInner(
+ /* r */targetRecord,
+ /* sourceRecord */ sourceRecord,
+ /* voiceSession */null,
+ /* voiceInteractor */ null,
+ /* startFlags */ 0,
+ /* doResume */true,
+ /* options */null,
+ /* inTask */null,
+ /* inTaskFragment */ taskFragment,
+ /* restrictedBgActivity */false,
+ /* intentGrants */null);
+
+ assertTrue(taskFragment.hasChild());
+ }
+
+ @Test
public void testLaunchCookie_newAndExistingTask() {
final ActivityStarter starter = prepareStarter(0, false);
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 f2418c6..a8ede13 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
@@ -82,7 +82,7 @@
mWm.mWindowContextListenerController.registerWindowContainerListener(clientToken,
dc.getImeContainer(), 1000 /* ownerUid */, TYPE_INPUT_METHOD_DIALOG,
null /* options */);
- return true;
+ return dc.getImeContainer().getConfiguration();
}).when(wms).attachWindowContextToDisplayArea(any(), eq(TYPE_INPUT_METHOD_DIALOG),
anyInt(), any());
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index a034ac2..d88fbee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -307,6 +307,29 @@
}
@Test
+ public void testBinderDiedAfterCancelWithDeferredScreenshot() throws Exception {
+ mWm.setRecentsAnimationController(mController);
+ final ActivityRecord homeActivity = createHomeActivity();
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
+ final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1");
+ activity.addWindow(win1);
+
+ initializeRecentsAnimationController(mController, homeActivity);
+ mController.setWillFinishToHome(true);
+
+ // Verify cancel is called with a snapshot and that we've created an overlay
+ spyOn(mWm.mTaskSnapshotController);
+ doReturn(mMockTaskSnapshot).when(mWm.mTaskSnapshotController).getSnapshot(anyInt(),
+ anyInt(), eq(false) /* restoreFromDisk */, eq(false) /* isLowResolution */);
+ mController.cancelAnimationWithScreenshot(true /* screenshot */);
+ verify(mMockRunner).onAnimationCanceled(any());
+
+ // Simulate process crashing and ensure the animation is still canceled
+ mController.binderDied();
+ verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, false);
+ }
+
+ @Test
public void testRecentViewInFixedPortraitWhenTopAppInLandscape() {
unblockDisplayRotation(mDefaultDisplay);
mWm.setRecentsAnimationController(mController);
@@ -701,6 +724,12 @@
// Continue the animation (simulating a call to cleanupScreenshot())
mController.continueDeferredCancelAnimation();
verify(mAnimationCallbacks).onAnimationFinished(REORDER_MOVE_TO_TOP, false);
+
+ // Assume home was moved to front so will-be-top callback should not be called.
+ homeActivity.moveFocusableActivityToTop("test");
+ spyOn(mDefaultDisplay.mFixedRotationTransitionListener);
+ mController.cleanupAnimation(REORDER_MOVE_TO_TOP);
+ verify(mDefaultDisplay.mFixedRotationTransitionListener, never()).notifyRecentsWillBeTop();
}
private ActivityRecord createHomeActivity() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
new file mode 100644
index 0000000..6bd8ad2
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.wm;
+
+import static android.window.TaskFragmentOrganizer.putExceptionInBundle;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.testing.Assert.assertThrows;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.content.res.Configuration;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+import android.view.SurfaceControl;
+import android.window.ITaskFragmentOrganizer;
+import android.window.TaskFragmentInfo;
+import android.window.TaskFragmentOrganizer;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Build/Install/Run:
+ * atest WmTests:TaskFragmentOrganizerControllerTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
+
+ private TaskFragmentOrganizerController mController;
+ private TaskFragmentOrganizer mOrganizer;
+ private ITaskFragmentOrganizer mIOrganizer;
+ private TaskFragment mTaskFragment;
+ private TaskFragmentInfo mTaskFragmentInfo;
+ private IBinder mFragmentToken;
+
+ @Before
+ public void setup() {
+ mController = mWm.mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController;
+ mOrganizer = new TaskFragmentOrganizer(Runnable::run);
+ mIOrganizer = mOrganizer.getIOrganizer();
+ mTaskFragment = mock(TaskFragment.class);
+ mTaskFragmentInfo = mock(TaskFragmentInfo.class);
+ mFragmentToken = new Binder();
+
+ spyOn(mController);
+ spyOn(mOrganizer);
+ doReturn(mIOrganizer).when(mTaskFragment).getTaskFragmentOrganizer();
+ doReturn(mTaskFragmentInfo).when(mTaskFragment).getTaskFragmentInfo();
+ doReturn(new SurfaceControl()).when(mTaskFragment).getSurfaceControl();
+ doReturn(mFragmentToken).when(mTaskFragment).getFragmentToken();
+ doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration();
+ }
+
+ @Test
+ public void testCallTaskFragmentCallbackWithoutRegister_throwsException() {
+ assertThrows(IllegalArgumentException.class, () -> mController
+ .onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment));
+
+ assertThrows(IllegalArgumentException.class, () -> mController
+ .onTaskFragmentInfoChanged(
+ mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment));
+
+ assertThrows(IllegalArgumentException.class, () -> mController
+ .onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment));
+
+ assertThrows(IllegalArgumentException.class, () -> mController
+ .onTaskFragmentParentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
+ mTaskFragment));
+ }
+
+ @Test
+ public void testOnTaskFragmentAppeared() {
+ mController.registerOrganizer(mIOrganizer);
+
+ mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
+
+ verify(mOrganizer).onTaskFragmentAppeared(any());
+ }
+
+ @Test
+ public void testOnTaskFragmentInfoChanged() {
+ mController.registerOrganizer(mIOrganizer);
+ mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
+
+ // No callback if the info is not changed.
+ doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any());
+ doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration();
+
+ mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
+ mTaskFragment);
+
+ verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
+
+ // Trigger callback if the info is changed.
+ doReturn(false).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any());
+
+ mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
+ mTaskFragment);
+
+ verify(mOrganizer).onTaskFragmentInfoChanged(mTaskFragmentInfo);
+ }
+
+ @Test
+ public void testOnTaskFragmentVanished() {
+ mController.registerOrganizer(mIOrganizer);
+
+ mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
+
+ verify(mOrganizer).onTaskFragmentVanished(any());
+ }
+
+ @Test
+ public void testOnTaskFragmentParentInfoChanged() {
+ mController.registerOrganizer(mIOrganizer);
+ final Task parent = mock(Task.class);
+ final Configuration parentConfig = new Configuration();
+ parentConfig.smallestScreenWidthDp = 10;
+ doReturn(parent).when(mTaskFragment).getParent();
+ doReturn(parentConfig).when(parent).getConfiguration();
+ doReturn(parent).when(parent).asTask();
+
+ mController.onTaskFragmentParentInfoChanged(
+ mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
+
+ verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any());
+
+ // No extra callback if the info is not changed.
+ clearInvocations(mOrganizer);
+
+ mController.onTaskFragmentParentInfoChanged(
+ mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
+
+ verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(any(), any());
+
+ // Trigger callback if the info is changed.
+ parentConfig.smallestScreenWidthDp = 100;
+
+ mController.onTaskFragmentParentInfoChanged(
+ mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
+
+ verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any());
+ }
+
+ @Test
+ public void testOnTaskFragmentError() throws RemoteException {
+ final IBinder errorCallbackToken = new Binder();
+ final Throwable exception = new IllegalArgumentException("Test exception");
+ final Bundle exceptionBundle = putExceptionInBundle(exception);
+
+ mIOrganizer.onTaskFragmentError(errorCallbackToken, exceptionBundle);
+
+ verify(mOrganizer).onTaskFragmentError(eq(errorCallbackToken), eq(exception));
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index d9aa871..83cdc3ba 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -107,9 +107,9 @@
Task tappedTask = createTaskInRootTask(tappedRootTask, 0 /* userId */);
spyOn(mWm.mAtmService);
- mWm.handleTaskFocusChange(tappedTask);
+ mWm.handleTaskFocusChange(tappedTask, null /* window */);
- verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId);
+ verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId, null);
}
@Test
@@ -128,9 +128,9 @@
Task tappedTask = createTaskInRootTask(tappedRootTask, 0 /* userId */);
spyOn(mWm.mAtmService);
- mWm.handleTaskFocusChange(tappedTask);
+ mWm.handleTaskFocusChange(tappedTask, null /* window */);
- verify(mWm.mAtmService, never()).setFocusedTask(tappedTask.mTaskId);
+ verify(mWm.mAtmService, never()).setFocusedTask(tappedTask.mTaskId, null);
}
@Test
@@ -151,9 +151,9 @@
Task tappedTask = createTaskInRootTask(tappedRootTask, 0 /* userId */);
spyOn(mWm.mAtmService);
- mWm.handleTaskFocusChange(tappedTask);
+ mWm.handleTaskFocusChange(tappedTask, null /* window */);
- verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId);
+ verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId, null);
}
@Test
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index e1bcb5f..e3485de 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -34,7 +34,10 @@
* <ul>
* <li>The component name of the associated connection service.</li>
* <li>A string identifier that is unique across {@code PhoneAccountHandle}s with the same
- * component name.</li>
+ * component name. Apps registering {@link PhoneAccountHandle}s should ensure that the
+ * {@link #getId()} provided does not expose personally identifying information. A
+ * {@link ConnectionService} should use an opaque token as the {@link PhoneAccountHandle}
+ * identifier.</li>
* </ul>
*
* Note: This Class requires a non-null {@link ComponentName} and {@link UserHandle} to operate
@@ -49,12 +52,35 @@
private final String mId;
private final UserHandle mUserHandle;
+ /**
+ * Creates a new {@link PhoneAccountHandle}.
+ *
+ * @param componentName The {@link ComponentName} of the {@link ConnectionService} which
+ * services this {@link PhoneAccountHandle}.
+ * @param id A string identifier that is unique across {@code PhoneAccountHandle}s with the same
+ * component name. Apps registering {@link PhoneAccountHandle}s should ensure that the
+ * ID provided does not expose personally identifying information. A
+ * {@link ConnectionService} should use an opaque token as the
+ * {@link PhoneAccountHandle} identifier.
+ */
public PhoneAccountHandle(
@NonNull ComponentName componentName,
@NonNull String id) {
this(componentName, id, Process.myUserHandle());
}
+ /**
+ * Creates a new {@link PhoneAccountHandle}.
+ *
+ * @param componentName The {@link ComponentName} of the {@link ConnectionService} which
+ * services this {@link PhoneAccountHandle}.
+ * @param id A string identifier that is unique across {@code PhoneAccountHandle}s with the same
+ * component name. Apps registering {@link PhoneAccountHandle}s should ensure that the
+ * ID provided does not expose personally identifying information. A
+ * {@link ConnectionService} should use an opaque token as the
+ * {@link PhoneAccountHandle} identifier.
+ * @param userHandle The {@link UserHandle} associated with this {@link PhoneAccountHandle}.
+ */
public PhoneAccountHandle(
@NonNull ComponentName componentName,
@NonNull String id,
@@ -80,17 +106,17 @@
* others supported by the connection service that created it.
* <p>
* A connection service must select identifiers that are stable for the lifetime of
- * their users' relationship with their service, across many Android devices. For example, a
- * good set of identifiers might be the email addresses with which with users registered for
- * their accounts with a particular service. Depending on how a service chooses to operate,
- * a bad set of identifiers might be an increasing series of integers
- * ({@code 0}, {@code 1}, {@code 2}, ...) that are generated locally on each phone and could
- * collide with values generated on other phones or after a data wipe of a given phone.
- *
+ * their users' relationship with their service, across many Android devices. The identifier
+ * should be a stable opaque token which uniquely identifies the user within the service.
+ * Depending on how a service chooses to operate, a bad set of identifiers might be an
+ * increasing series of integers ({@code 0}, {@code 1}, {@code 2}, ...) that are generated
+ * locally on each phone and could collide with values generated on other phones or after a data
+ * wipe of a given phone.
+ * <p>
* Important: A non-unique identifier could cause non-deterministic call-log backup/restore
* behavior.
*
- * @return A service-specific unique identifier for this {@code PhoneAccountHandle}.
+ * @return A service-specific unique opaque identifier for this {@code PhoneAccountHandle}.
*/
public String getId() {
return mId;
@@ -157,7 +183,8 @@
}
}
- public static final @android.annotation.NonNull Creator<PhoneAccountHandle> CREATOR = new Creator<PhoneAccountHandle>() {
+ public static final @android.annotation.NonNull Creator<PhoneAccountHandle> CREATOR =
+ new Creator<PhoneAccountHandle>() {
@Override
public PhoneAccountHandle createFromParcel(Parcel in) {
return new PhoneAccountHandle(in);
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 7ba6f36..53922ed 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -37,6 +37,7 @@
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.IIntegerConsumer;
@@ -447,8 +448,9 @@
executor.execute(() -> stateCallback.accept(result));
}
});
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ } catch (ServiceSpecificException | RemoteException e) {
+ Log.w("ImsMmTelManager", "Error getting registration state: " + e);
+ executor.execute(() -> stateCallback.accept(REGISTRATION_STATE_NOT_REGISTERED));
}
}
@@ -488,8 +490,10 @@
executor.execute(() -> transportTypeCallback.accept(result));
}
});
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ } catch (ServiceSpecificException | RemoteException e) {
+ Log.w("ImsMmTelManager", "Error getting transport type: " + e);
+ executor.execute(() -> transportTypeCallback.accept(
+ AccessNetworkConstants.TRANSPORT_TYPE_INVALID));
}
}
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 3700026..91c5324 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -302,8 +302,10 @@
executor.execute(() -> stateCallback.accept(result));
}
});
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ } catch (ServiceSpecificException | RemoteException e) {
+ Log.w(TAG, "Get registration state error: " + e);
+ executor.execute(() -> stateCallback.accept(
+ RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED));
}
}
@@ -346,8 +348,10 @@
executor.execute(() -> transportTypeCallback.accept(result));
}
});
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ } catch (ServiceSpecificException | RemoteException e) {
+ Log.w(TAG, "Get registration transport type error: " + e);
+ executor.execute(() -> transportTypeCallback.accept(
+ AccessNetworkConstants.TRANSPORT_TYPE_INVALID));
}
}
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index d6b3c27..9cdaef7 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -212,6 +212,28 @@
assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex");
}
+ TestApp apex1 = new TestApp("TestRebootlessApexV1", "test.apex.rebootless", 1,
+ /* isApex= */ true, "test.rebootless_apex_v1.apex");
+ Install.single(apex1).commit();
+
+ {
+ PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", PackageManager.MATCH_APEX);
+ assertThat(apex.getLongVersionCode()).isEqualTo(1);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
+ .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
+ assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active");
+ }
+ {
+ PackageInfo apex = pm.getPackageInfo("test.apex.rebootless",
+ PackageManager.MATCH_APEX | PackageManager.MATCH_FACTORY_ONLY);
+ assertThat(apex.getLongVersionCode()).isEqualTo(1);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
+ assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex");
+ }
+
TestApp apex2 = new TestApp("TestRebootlessApexV1", "test.apex.rebootless", 2,
/* isApex= */ true, "test.rebootless_apex_v2.apex");
Install.single(apex2).commit();
@@ -224,6 +246,15 @@
.isEqualTo(ApplicationInfo.FLAG_INSTALLED);
assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active");
}
+ {
+ PackageInfo apex = pm.getPackageInfo("test.apex.rebootless",
+ PackageManager.MATCH_APEX | PackageManager.MATCH_FACTORY_ONLY);
+ assertThat(apex.getLongVersionCode()).isEqualTo(1);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
+ assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex");
+ }
}
private static void assertSessionFailedWithMessage(int sessionId, String msg) {