Merge "Adding tests for temporary and renewable trust" into tm-dev
diff --git a/Android.bp b/Android.bp
index 753cefc..edaa11e3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -97,6 +97,7 @@
":platform-compat-native-aidl",
// AIDL sources from external directories
+ ":android.hardware.gnss-V2-java-source",
":android.hardware.graphics.common-V3-java-source",
":android.hardware.security.keymint-V2-java-source",
":android.hardware.security.secureclock-V1-java-source",
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index 18f63b7..23056b5 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -17,6 +17,7 @@
package com.android.server.job;
import static com.android.server.job.JobSchedulerService.MAX_JOB_CONTEXTS_COUNT;
+import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.annotation.IntDef;
@@ -32,9 +33,11 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
+import android.os.BatteryStats;
import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArraySet;
@@ -51,19 +54,24 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IBatteryStats;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.util.StatLogger;
import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.LocalServices;
import com.android.server.job.controllers.JobStatus;
import com.android.server.job.controllers.StateController;
+import com.android.server.job.restrictions.JobRestriction;
import com.android.server.pm.UserManagerInternal;
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* This class decides, given the various configuration and the system status, which jobs can start
@@ -278,6 +286,11 @@
String[] mRecycledShouldStopJobReason = new String[MAX_JOB_CONTEXTS_COUNT];
+ /**
+ * Set of JobServiceContexts that we use to run jobs.
+ */
+ final List<JobServiceContext> mActiveServices = new ArrayList<>();
+
private final ArraySet<JobStatus> mRunningJobs = new ArraySet<>();
private final WorkCountTracker mWorkCountTracker = new WorkCountTracker();
@@ -358,6 +371,20 @@
onInteractiveStateChanged(mPowerManager.isInteractive());
}
+ /**
+ * Called when the boot phase reaches
+ * {@link com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START}.
+ */
+ void onThirdPartyAppsCanStart() {
+ final IBatteryStats batteryStats = IBatteryStats.Stub.asInterface(
+ ServiceManager.getService(BatteryStats.SERVICE_NAME));
+ for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
+ mActiveServices.add(
+ new JobServiceContext(mService, this, batteryStats,
+ mService.mJobPackageTracker, mContext.getMainLooper()));
+ }
+ }
+
@GuardedBy("mLock")
void onAppRemovedLocked(String pkgName, int uid) {
final PackageStats packageStats = mActivePkgStats.get(UserHandle.getUserId(uid), pkgName);
@@ -390,6 +417,7 @@
case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
if (mPowerManager != null && mPowerManager.isDeviceIdleMode()) {
synchronized (mLock) {
+ stopUnexemptedJobsForDoze();
stopLongRunningJobsLocked("deep doze");
}
}
@@ -471,6 +499,11 @@
}
@GuardedBy("mLock")
+ ArraySet<JobStatus> getRunningJobsLocked() {
+ return mRunningJobs;
+ }
+
+ @GuardedBy("mLock")
boolean isJobRunningLocked(JobStatus job) {
return mRunningJobs.contains(job);
}
@@ -546,7 +579,7 @@
}
final List<JobStatus> pendingJobs = mService.mPendingJobs;
- final List<JobServiceContext> activeServices = mService.mActiveServices;
+ final List<JobServiceContext> activeServices = mActiveServices;
// To avoid GC churn, we recycle the arrays.
JobStatus[] contextIdToJobMap = mRecycledAssignContextIdToJobMap;
@@ -719,9 +752,44 @@
}
@GuardedBy("mLock")
+ boolean stopJobOnServiceContextLocked(JobStatus job,
+ @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
+ if (!mRunningJobs.contains(job)) {
+ return false;
+ }
+
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ JobServiceContext jsc = mActiveServices.get(i);
+ final JobStatus executing = jsc.getRunningJobLocked();
+ if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
+ jsc.cancelExecutingJobLocked(reason, internalReasonCode, debugReason);
+ return true;
+ }
+ }
+ Slog.wtf(TAG, "Couldn't find running job on a context");
+ mRunningJobs.remove(job);
+ return false;
+ }
+
+ @GuardedBy("mLock")
+ private void stopUnexemptedJobsForDoze() {
+ // When becoming idle, make sure no jobs are actively running,
+ // except those using the idle exemption flag.
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ JobServiceContext jsc = mActiveServices.get(i);
+ final JobStatus executing = jsc.getRunningJobLocked();
+ if (executing != null && !executing.canRunInDoze()) {
+ jsc.cancelExecutingJobLocked(JobParameters.STOP_REASON_DEVICE_STATE,
+ JobParameters.INTERNAL_STOP_REASON_DEVICE_IDLE,
+ "cancelled due to doze");
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
private void stopLongRunningJobsLocked(@NonNull String debugReason) {
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; ++i) {
- final JobServiceContext jsc = mService.mActiveServices.get(i);
+ final JobServiceContext jsc = mActiveServices.get(i);
final JobStatus jobStatus = jsc.getRunningJobLocked();
if (jobStatus != null && !jsc.isWithinExecutionGuaranteeTime()) {
@@ -731,6 +799,41 @@
}
}
+ @GuardedBy("mLock")
+ void stopNonReadyActiveJobsLocked() {
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ JobServiceContext serviceContext = mActiveServices.get(i);
+ final JobStatus running = serviceContext.getRunningJobLocked();
+ if (running == null) {
+ continue;
+ }
+ if (!running.isReady()) {
+ if (running.getEffectiveStandbyBucket() == RESTRICTED_INDEX
+ && running.getStopReason() == JobParameters.STOP_REASON_APP_STANDBY) {
+ serviceContext.cancelExecutingJobLocked(
+ running.getStopReason(),
+ JobParameters.INTERNAL_STOP_REASON_RESTRICTED_BUCKET,
+ "cancelled due to restricted bucket");
+ } else {
+ serviceContext.cancelExecutingJobLocked(
+ running.getStopReason(),
+ JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
+ "cancelled due to unsatisfied constraints");
+ }
+ } else {
+ final JobRestriction restriction = mService.checkIfRestricted(running);
+ if (restriction != null) {
+ final int internalReasonCode = restriction.getInternalReason();
+ serviceContext.cancelExecutingJobLocked(restriction.getReason(),
+ internalReasonCode,
+ "restricted due to "
+ + JobParameters.getInternalReasonCodeDescription(
+ internalReasonCode));
+ }
+ }
+ }
+ }
+
private void noteConcurrency() {
mService.mJobPackageTracker.noteConcurrency(mRunningJobs.size(),
// TODO: log per type instead of only TOP
@@ -1078,6 +1181,24 @@
}
@GuardedBy("mLock")
+ boolean executeTimeoutCommandLocked(PrintWriter pw, String pkgName, int userId,
+ boolean hasJobId, int jobId) {
+ boolean foundSome = false;
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ final JobServiceContext jc = mActiveServices.get(i);
+ final JobStatus js = jc.getRunningJobLocked();
+ if (jc.timeoutIfExecutingLocked(pkgName, userId, hasJobId, jobId, "shell")) {
+ foundSome = true;
+ pw.print("Timing out: ");
+ js.printUniqueId(pw);
+ pw.print(" ");
+ pw.println(js.getServiceComponent().flattenToShortString());
+ }
+ }
+ return foundSome;
+ }
+
+ @GuardedBy("mLock")
private String printPendingQueueLocked() {
StringBuilder s = new StringBuilder("Pending queue: ");
Iterator<JobStatus> it = mService.mPendingJobs.iterator();
@@ -1200,6 +1321,43 @@
}
}
+ @GuardedBy("mLock")
+ void dumpActiveJobsLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate,
+ long nowElapsed, long nowUptime) {
+ pw.println("Active jobs:");
+ pw.increaseIndent();
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ JobServiceContext jsc = mActiveServices.get(i);
+ final JobStatus job = jsc.getRunningJobLocked();
+
+ if (job != null && !predicate.test(job)) {
+ continue;
+ }
+
+ pw.print("Slot #"); pw.print(i); pw.print(": ");
+ jsc.dumpLocked(pw, nowElapsed);
+
+ if (job != null) {
+ pw.increaseIndent();
+
+ pw.increaseIndent();
+ job.dump(pw, false, nowElapsed);
+ pw.decreaseIndent();
+
+ pw.print("Evaluated bias: ");
+ pw.println(JobInfo.getBiasString(job.lastEvaluatedBias));
+
+ pw.print("Active at ");
+ TimeUtils.formatDuration(job.madeActive - nowUptime, pw);
+ pw.print(", pending for ");
+ TimeUtils.formatDuration(job.madeActive - job.madePending, pw);
+ pw.decreaseIndent();
+ pw.println();
+ }
+ }
+ pw.decreaseIndent();
+ }
+
public void dumpProtoLocked(ProtoOutputStream proto, long tag, long now, long nowRealtime) {
final long token = proto.start(tag);
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 b936278..3d74bc9 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -57,7 +57,6 @@
import android.net.Uri;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
-import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.Binder;
import android.os.Handler;
@@ -67,7 +66,6 @@
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
@@ -90,7 +88,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IBatteryStats;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
@@ -100,7 +97,6 @@
import com.android.server.DeviceIdleInternal;
import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.LocalServices;
-import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
import com.android.server.job.controllers.BackgroundJobsController;
import com.android.server.job.controllers.BatteryController;
@@ -243,12 +239,6 @@
static final int MSG_CHECK_CHANGED_JOB_LIST = 8;
static final int MSG_CHECK_MEDIA_EXEMPTION = 9;
- /**
- * Track Services that have currently active or pending jobs. The index is provided by
- * {@link JobStatus#getServiceToken()}
- */
- final List<JobServiceContext> mActiveServices = new ArrayList<>();
-
/** List of controllers that will notify this service of updates to jobs. */
final List<StateController> mControllers;
/**
@@ -307,7 +297,6 @@
PackageManagerInternal mLocalPM;
ActivityManagerInternal mActivityManagerInternal;
- IBatteryStats mBatteryStats;
DeviceIdleInternal mLocalDeviceIdleController;
@VisibleForTesting
AppStateTrackerImpl mAppStateTracker;
@@ -1578,7 +1567,8 @@
mJobPackageTracker.noteNonpending(cancelled);
}
// Cancel if running.
- stopJobOnServiceContextLocked(cancelled, reason, internalReasonCode, debugReason);
+ mConcurrencyManager.stopJobOnServiceContextLocked(
+ cancelled, reason, internalReasonCode, debugReason);
// If this is a replacement, bring in the new version of the job
if (incomingJob != null) {
if (DEBUG) Slog.i(TAG, "Tracking replacement job " + incomingJob.toShortString());
@@ -1627,19 +1617,7 @@
if (DEBUG) {
Slog.d(TAG, "Doze state changed: " + deviceIdle);
}
- if (deviceIdle) {
- // When becoming idle, make sure no jobs are actively running,
- // except those using the idle exemption flag.
- for (int i=0; i<mActiveServices.size(); i++) {
- JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus executing = jsc.getRunningJobLocked();
- if (executing != null && !executing.canRunInDoze()) {
- jsc.cancelExecutingJobLocked(JobParameters.STOP_REASON_DEVICE_STATE,
- JobParameters.INTERNAL_STOP_REASON_DEVICE_IDLE,
- "cancelled due to doze");
- }
- }
- } else {
+ if (!deviceIdle) {
// When coming out of idle, allow thing to start back up.
if (mReadyToRock) {
if (mLocalDeviceIdleController != null) {
@@ -1682,10 +1660,10 @@
// active is true if pending queue contains jobs OR some job is running.
boolean active = mPendingJobs.size() > 0;
if (mPendingJobs.size() <= 0) {
- for (int i=0; i<mActiveServices.size(); i++) {
- final JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus job = jsc.getRunningJobLocked();
- if (job != null && !job.canRunInDoze()) {
+ final ArraySet<JobStatus> runningJobs = mConcurrencyManager.getRunningJobsLocked();
+ for (int i = runningJobs.size() - 1; i >= 0; --i) {
+ final JobStatus job = runningJobs.valueAt(i);
+ if (!job.canRunInDoze()) {
// We will report active if we have a job running and it does not have an
// exception that allows it to run in Doze.
active = true;
@@ -1895,16 +1873,9 @@
synchronized (mLock) {
// Let's go!
mReadyToRock = true;
- mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
- BatteryStats.SERVICE_NAME));
mLocalDeviceIdleController =
LocalServices.getService(DeviceIdleInternal.class);
- // Create the "runners".
- for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
- mActiveServices.add(
- new JobServiceContext(this, mConcurrencyManager, mBatteryStats,
- mJobPackageTracker, getContext().getMainLooper()));
- }
+ mConcurrencyManager.onThirdPartyAppsCanStart();
// Attach jobs to their controllers.
mJobs.forEachJob((job) -> {
for (int controller = 0; controller < mControllers.size(); controller++) {
@@ -1961,19 +1932,6 @@
return removed;
}
- private boolean stopJobOnServiceContextLocked(JobStatus job,
- @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
- for (int i = 0; i < mActiveServices.size(); i++) {
- JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus executing = jsc.getRunningJobLocked();
- if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
- jsc.cancelExecutingJobLocked(reason, internalReasonCode, debugReason);
- return true;
- }
- }
- return false;
- }
-
/** Return {@code true} if the specified job is currently executing. */
@GuardedBy("mLock")
public boolean isCurrentlyRunningLocked(JobStatus job) {
@@ -2383,7 +2341,8 @@
* - if passes all the restrictions or has {@link JobInfo#BIAS_FOREGROUND_SERVICE} bias
* or higher.
*/
- private JobRestriction checkIfRestricted(JobStatus job) {
+ @GuardedBy("mLock")
+ JobRestriction checkIfRestricted(JobStatus job) {
if (evaluateJobBiasLocked(job) >= JobInfo.BIAS_FOREGROUND_SERVICE) {
// Jobs with BIAS_FOREGROUND_SERVICE or higher should not be restricted
return null;
@@ -2397,38 +2356,9 @@
return null;
}
+ @GuardedBy("mLock")
private void stopNonReadyActiveJobsLocked() {
- for (int i=0; i<mActiveServices.size(); i++) {
- JobServiceContext serviceContext = mActiveServices.get(i);
- final JobStatus running = serviceContext.getRunningJobLocked();
- if (running == null) {
- continue;
- }
- if (!running.isReady()) {
- if (running.getEffectiveStandbyBucket() == RESTRICTED_INDEX
- && running.getStopReason() == JobParameters.STOP_REASON_APP_STANDBY) {
- serviceContext.cancelExecutingJobLocked(
- running.getStopReason(),
- JobParameters.INTERNAL_STOP_REASON_RESTRICTED_BUCKET,
- "cancelled due to restricted bucket");
- } else {
- serviceContext.cancelExecutingJobLocked(
- running.getStopReason(),
- JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
- "cancelled due to unsatisfied constraints");
- }
- } else {
- final JobRestriction restriction = checkIfRestricted(running);
- if (restriction != null) {
- final int internalReasonCode = restriction.getInternalReason();
- serviceContext.cancelExecutingJobLocked(restriction.getReason(),
- internalReasonCode,
- "restricted due to "
- + JobParameters.getInternalReasonCodeDescription(
- internalReasonCode));
- }
- }
- }
+ mConcurrencyManager.stopNonReadyActiveJobsLocked();
}
/**
@@ -2598,7 +2528,7 @@
debugReason = "couldn't figure out why the job should stop running";
}
}
- stopJobOnServiceContextLocked(job, job.getStopReason(),
+ mConcurrencyManager.stopJobOnServiceContextLocked(job, job.getStopReason(),
internalStopReason, debugReason);
} else if (mPendingJobs.remove(job)) {
noteJobNonPending(job);
@@ -3516,9 +3446,11 @@
final ArrayList<JobInfo> runningJobs;
synchronized (mLock) {
- runningJobs = new ArrayList<>(mActiveServices.size());
- for (JobServiceContext jsc : mActiveServices) {
- final JobStatus job = jsc.getRunningJobLocked();
+ final ArraySet<JobStatus> runningJobStatuses =
+ mConcurrencyManager.getRunningJobsLocked();
+ runningJobs = new ArrayList<>(runningJobStatuses.size());
+ for (int i = runningJobStatuses.size() - 1; i >= 0; --i) {
+ final JobStatus job = runningJobStatuses.valueAt(i);
if (job != null) {
runningJobs.add(job.getJob());
}
@@ -3599,18 +3531,8 @@
}
synchronized (mLock) {
- boolean foundSome = false;
- for (int i = 0; i < mActiveServices.size(); i++) {
- final JobServiceContext jc = mActiveServices.get(i);
- final JobStatus js = jc.getRunningJobLocked();
- if (jc.timeoutIfExecutingLocked(pkgName, userId, hasJobId, jobId, "shell")) {
- foundSome = true;
- pw.print("Timing out: ");
- js.printUniqueId(pw);
- pw.print(" ");
- pw.println(js.getServiceComponent().flattenToShortString());
- }
- }
+ final boolean foundSome = mConcurrencyManager.executeTimeoutCommandLocked(pw,
+ pkgName, userId, hasJobId, jobId);
if (!foundSome) {
pw.println("No matching executing jobs found.");
}
@@ -4037,38 +3959,7 @@
pw.decreaseIndent();
pw.println();
- pw.println("Active jobs:");
- pw.increaseIndent();
- for (int i=0; i<mActiveServices.size(); i++) {
- JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus job = jsc.getRunningJobLocked();
-
- if (job != null && !predicate.test(job)) {
- continue;
- }
-
- pw.print("Slot #"); pw.print(i); pw.print(": ");
- jsc.dumpLocked(pw, nowElapsed);
-
- if (job != null) {
- pw.increaseIndent();
-
- pw.increaseIndent();
- job.dump(pw, false, nowElapsed);
- pw.decreaseIndent();
-
- pw.print("Evaluated bias: ");
- pw.println(JobInfo.getBiasString(job.lastEvaluatedBias));
-
- pw.print("Active at ");
- TimeUtils.formatDuration(job.madeActive - nowUptime, pw);
- pw.print(", pending for ");
- TimeUtils.formatDuration(job.madeActive - job.madePending, pw);
- pw.decreaseIndent();
- pw.println();
- }
- }
- pw.decreaseIndent();
+ mConcurrencyManager.dumpActiveJobsLocked(pw, predicate, nowElapsed, nowUptime);
pw.println();
boolean recentPrinted = false;
@@ -4228,45 +4119,6 @@
proto.end(pjToken);
}
- for (JobServiceContext jsc : mActiveServices) {
- final long ajToken = proto.start(JobSchedulerServiceDumpProto.ACTIVE_JOBS);
- final JobStatus job = jsc.getRunningJobLocked();
-
- if (job == null) {
- final long ijToken = proto.start(ActiveJob.INACTIVE);
-
- proto.write(ActiveJob.InactiveJob.TIME_SINCE_STOPPED_MS,
- nowElapsed - jsc.mStoppedTime);
- if (jsc.mStoppedReason != null) {
- proto.write(ActiveJob.InactiveJob.STOPPED_REASON,
- jsc.mStoppedReason);
- }
-
- proto.end(ijToken);
- } else {
- final long rjToken = proto.start(ActiveJob.RUNNING);
-
- job.writeToShortProto(proto, ActiveJob.RunningJob.INFO);
-
- proto.write(ActiveJob.RunningJob.RUNNING_DURATION_MS,
- nowElapsed - jsc.getExecutionStartTimeElapsed());
- proto.write(ActiveJob.RunningJob.TIME_UNTIL_TIMEOUT_MS,
- jsc.getTimeoutElapsed() - nowElapsed);
-
- job.dump(proto, ActiveJob.RunningJob.DUMP, false, nowElapsed);
-
- proto.write(ActiveJob.RunningJob.EVALUATED_PRIORITY,
- evaluateJobBiasLocked(job));
-
- proto.write(ActiveJob.RunningJob.TIME_SINCE_MADE_ACTIVE_MS,
- nowUptime - job.madeActive);
- proto.write(ActiveJob.RunningJob.PENDING_DURATION_MS,
- job.madeActive - job.madePending);
-
- proto.end(rjToken);
- }
- proto.end(ajToken);
- }
if (filterUid == -1) {
proto.write(JobSchedulerServiceDumpProto.IS_READY_TO_ROCK, mReadyToRock);
proto.write(JobSchedulerServiceDumpProto.REPORTED_ACTIVE, mReportedActive);
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 efcf14f..30fdb1e 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
@@ -441,11 +441,6 @@
/** The reason a job most recently went from ready to not ready. */
private int mReasonReadyToUnready = JobParameters.STOP_REASON_UNDEFINED;
- /** Provide a handle to the service that this job will be run on. */
- public int getServiceToken() {
- return callingUid;
- }
-
/**
* Core constructor for JobStatus instances. All other ctors funnel down to this one.
*
diff --git a/core/api/current.txt b/core/api/current.txt
index b5493a3..3f12b6c 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5630,6 +5630,7 @@
method public boolean onException(Object, Throwable);
method public void onStart();
method public void removeMonitor(android.app.Instrumentation.ActivityMonitor);
+ method public void resetInTouchMode();
method public void runOnMainSync(Runnable);
method public void sendCharacterSync(int);
method public void sendKeyDownUpSync(int);
@@ -5814,6 +5815,7 @@
public class LocaleManager {
method @NonNull public android.os.LocaleList getApplicationLocales();
method @NonNull @RequiresPermission(value="android.permission.READ_APP_SPECIFIC_LOCALES", conditional=true) public android.os.LocaleList getApplicationLocales(@NonNull String);
+ method @NonNull public android.os.LocaleList getSystemLocales();
method public void setApplicationLocales(@NonNull android.os.LocaleList);
}
@@ -6644,6 +6646,15 @@
public final class PictureInPictureParams implements android.os.Parcelable {
method public int describeContents();
+ method @NonNull public java.util.List<android.app.RemoteAction> getActions();
+ method @Nullable public android.util.Rational getAspectRatio();
+ method @Nullable public android.app.RemoteAction getCloseAction();
+ method @Nullable public android.util.Rational getExpandedAspectRatio();
+ method @Nullable public android.graphics.Rect getSourceRectHint();
+ method @Nullable public CharSequence getSubtitle();
+ method @Nullable public CharSequence getTitle();
+ method public boolean isAutoEnterEnabled();
+ method public boolean isSeamlessResizeEnabled();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.PictureInPictureParams> CREATOR;
}
@@ -9726,8 +9737,8 @@
method @Nullable public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int);
method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void removeStickyBroadcast(@RequiresPermission android.content.Intent);
method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void removeStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
- method public void revokeOwnPermissionOnKill(@NonNull String);
- method public void revokeOwnPermissionsOnKill(@NonNull java.util.Collection<java.lang.String>);
+ method public void revokeSelfPermissionOnKill(@NonNull String);
+ method public void revokeSelfPermissionsOnKill(@NonNull java.util.Collection<java.lang.String>);
method public abstract void revokeUriPermission(android.net.Uri, int);
method public abstract void revokeUriPermission(String, android.net.Uri, int);
method public abstract void sendBroadcast(@RequiresPermission android.content.Intent);
@@ -10115,12 +10126,16 @@
method @Nullable public long[] getLongArrayExtra(String);
method public long getLongExtra(String, long);
method @Nullable public String getPackage();
- method @Nullable public android.os.Parcelable[] getParcelableArrayExtra(String);
- method @Nullable public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(String);
- method @Nullable public <T extends android.os.Parcelable> T getParcelableExtra(String);
+ method @Deprecated @Nullable public android.os.Parcelable[] getParcelableArrayExtra(String);
+ method @Nullable public <T> T[] getParcelableArrayExtra(@Nullable String, @NonNull Class<T>);
+ method @Deprecated @Nullable public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(String);
+ method @Nullable public <T> java.util.ArrayList<T> getParcelableArrayListExtra(@Nullable String, @NonNull Class<? extends T>);
+ method @Deprecated @Nullable public <T extends android.os.Parcelable> T getParcelableExtra(String);
+ method @Nullable public <T> T getParcelableExtra(@Nullable String, @NonNull Class<T>);
method @Nullable public String getScheme();
method @Nullable public android.content.Intent getSelector();
- method @Nullable public java.io.Serializable getSerializableExtra(String);
+ method @Deprecated @Nullable public java.io.Serializable getSerializableExtra(String);
+ method @Nullable public <T extends java.io.Serializable> T getSerializableExtra(@Nullable String, @NonNull Class<T>);
method @Nullable public short[] getShortArrayExtra(String);
method public short getShortExtra(String, short);
method @Nullable public android.graphics.Rect getSourceBounds();
@@ -19477,26 +19492,26 @@
method @NonNull public static String convert(@FloatRange double, int);
method @FloatRange public static double convert(@NonNull String);
method public int describeContents();
- method public static void distanceBetween(@FloatRange double, @FloatRange double, @FloatRange double, @FloatRange double, float[]);
- method @FloatRange public float distanceTo(@NonNull android.location.Location);
- method public void dump(@NonNull android.util.Printer, @Nullable String);
- method @FloatRange public float getAccuracy();
+ method public static void distanceBetween(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, float[]);
+ method @FloatRange(from=0.0) public float distanceTo(@NonNull android.location.Location);
+ method @Deprecated public void dump(@NonNull android.util.Printer, @Nullable String);
+ method @FloatRange(from=0.0) public float getAccuracy();
method @FloatRange public double getAltitude();
- method @FloatRange(from=0.0f, to=360.0f, toInclusive=false) public float getBearing();
- method @FloatRange public float getBearingAccuracyDegrees();
- method @IntRange public long getElapsedRealtimeAgeMillis();
- method @IntRange public long getElapsedRealtimeAgeMillis(@IntRange long);
- method @IntRange public long getElapsedRealtimeMillis();
- method @IntRange public long getElapsedRealtimeNanos();
- method @FloatRange public double getElapsedRealtimeUncertaintyNanos();
+ method @FloatRange(from=0.0, to=360.0, toInclusive=false) public float getBearing();
+ method @FloatRange(from=0.0) public float getBearingAccuracyDegrees();
+ method @IntRange(from=0) public long getElapsedRealtimeAgeMillis();
+ method public long getElapsedRealtimeAgeMillis(@IntRange(from=0) long);
+ method @IntRange(from=0) public long getElapsedRealtimeMillis();
+ method @IntRange(from=0) public long getElapsedRealtimeNanos();
+ method @FloatRange(from=0.0) public double getElapsedRealtimeUncertaintyNanos();
method @Nullable public android.os.Bundle getExtras();
- method @FloatRange public double getLatitude();
- method @FloatRange public double getLongitude();
+ method @FloatRange(from=-90.0, to=90.0) public double getLatitude();
+ method @FloatRange(from=-180.0, to=180.0) public double getLongitude();
method @Nullable public String getProvider();
- method @FloatRange public float getSpeed();
- method @FloatRange public float getSpeedAccuracyMetersPerSecond();
- method @IntRange public long getTime();
- method @FloatRange public float getVerticalAccuracyMeters();
+ method @FloatRange(from=0.0) public float getSpeed();
+ method @FloatRange(from=0.0) public float getSpeedAccuracyMetersPerSecond();
+ method @IntRange(from=0) public long getTime();
+ method @FloatRange(from=0.0) public float getVerticalAccuracyMeters();
method public boolean hasAccuracy();
method public boolean hasAltitude();
method public boolean hasBearing();
@@ -19518,21 +19533,21 @@
method public void removeVerticalAccuracy();
method public void reset();
method public void set(@NonNull android.location.Location);
- method public void setAccuracy(@FloatRange float);
+ method public void setAccuracy(@FloatRange(from=0.0) float);
method public void setAltitude(@FloatRange double);
method public void setBearing(@FloatRange(fromInclusive=false, toInclusive=false) float);
- method public void setBearingAccuracyDegrees(@FloatRange float);
- method public void setElapsedRealtimeNanos(@IntRange long);
- method public void setElapsedRealtimeUncertaintyNanos(@FloatRange double);
+ method public void setBearingAccuracyDegrees(@FloatRange(from=0.0) float);
+ method public void setElapsedRealtimeNanos(@IntRange(from=0) long);
+ method public void setElapsedRealtimeUncertaintyNanos(@FloatRange(from=0.0) double);
method public void setExtras(@Nullable android.os.Bundle);
- method public void setLatitude(@FloatRange double);
- method public void setLongitude(@FloatRange double);
+ method public void setLatitude(@FloatRange(from=-90.0, to=90.0) double);
+ method public void setLongitude(@FloatRange(from=-180.0, to=180.0) double);
method public void setMock(boolean);
method public void setProvider(@Nullable String);
- method public void setSpeed(@FloatRange float);
- method public void setSpeedAccuracyMetersPerSecond(@FloatRange float);
- method public void setTime(@IntRange long);
- method public void setVerticalAccuracyMeters(@FloatRange float);
+ method public void setSpeed(@FloatRange(from=0.0) float);
+ method public void setSpeedAccuracyMetersPerSecond(@FloatRange(from=0.0) float);
+ method public void setTime(@IntRange(from=0) long);
+ method public void setVerticalAccuracyMeters(@FloatRange(from=0.0) float);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.location.Location> CREATOR;
field public static final int FORMAT_DEGREES = 0; // 0x0
@@ -22176,7 +22191,7 @@
field public static final String KEY_AAC_DRC_OUTPUT_LOUDNESS = "aac-drc-output-loudness";
field public static final String KEY_AAC_DRC_TARGET_REFERENCE_LEVEL = "aac-target-ref-level";
field public static final String KEY_AAC_ENCODED_TARGET_LEVEL = "aac-encoded-target-level";
- field public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
+ field @Deprecated public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
field public static final String KEY_AAC_PROFILE = "aac-profile";
field public static final String KEY_AAC_SBR_MODE = "aac-sbr-mode";
field public static final String KEY_ALLOW_FRAME_DROP = "allow-frame-drop";
@@ -23538,17 +23553,24 @@
}
public class Spatializer {
+ method public void addOnHeadTrackerAvailableListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnHeadTrackerAvailableListener);
method public void addOnSpatializerStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
method public boolean canBeSpatialized(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioFormat);
method public int getImmersiveAudioLevel();
method public boolean isAvailable();
method public boolean isEnabled();
+ method public boolean isHeadTrackerAvailable();
+ method public void removeOnHeadTrackerAvailableListener(@NonNull android.media.Spatializer.OnHeadTrackerAvailableListener);
method public void removeOnSpatializerStateChangedListener(@NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
field public static final int SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL = 1; // 0x1
field public static final int SPATIALIZER_IMMERSIVE_LEVEL_NONE = 0; // 0x0
field public static final int SPATIALIZER_IMMERSIVE_LEVEL_OTHER = -1; // 0xffffffff
}
+ public static interface Spatializer.OnHeadTrackerAvailableListener {
+ method public void onHeadTrackerAvailableChanged(@NonNull android.media.Spatializer, boolean);
+ }
+
public static interface Spatializer.OnSpatializerStateChangedListener {
method public void onSpatializerAvailableChanged(@NonNull android.media.Spatializer, boolean);
method public void onSpatializerEnabledChanged(@NonNull android.media.Spatializer, boolean);
@@ -25181,17 +25203,23 @@
}
public final class CommandRequest extends android.media.tv.BroadcastInfoRequest implements android.os.Parcelable {
- ctor public CommandRequest(int, int, @NonNull String, @NonNull String, @NonNull String);
+ ctor public CommandRequest(int, int, @NonNull String, @NonNull String, @NonNull String, @NonNull String);
+ method @NonNull public String getArgumentType();
method @NonNull public String getArguments();
method @NonNull public String getName();
- method @NonNull public String getNameSpace();
+ method @NonNull public String getNamespace();
+ field public static final String ARGUMENT_TYPE_JSON = "json";
+ field public static final String ARGUMENT_TYPE_XML = "xml";
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.CommandRequest> CREATOR;
}
public final class CommandResponse extends android.media.tv.BroadcastInfoResponse implements android.os.Parcelable {
- ctor public CommandResponse(int, int, int, @Nullable String);
+ ctor public CommandResponse(int, int, int, @Nullable String, @NonNull String);
method @Nullable public String getResponse();
+ method @NonNull public String getResponseType();
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.CommandResponse> CREATOR;
+ field public static final String RESPONSE_TYPE_JSON = "json";
+ field public static final String RESPONSE_TYPE_XML = "xml";
}
public final class DsmccRequest extends android.media.tv.BroadcastInfoRequest implements android.os.Parcelable {
@@ -25256,7 +25284,7 @@
ctor public StreamEventResponse(int, int, int, int, long, @Nullable byte[]);
method @Nullable public byte[] getData();
method public int getEventId();
- method public long getNpt();
+ method public long getNptMillis();
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.StreamEventResponse> CREATOR;
}
@@ -25286,7 +25314,7 @@
public final class TimelineResponse extends android.media.tv.BroadcastInfoResponse implements android.os.Parcelable {
ctor public TimelineResponse(int, int, int, @Nullable String, int, int, long, long);
- method @Nullable public String getSelector();
+ method @Nullable public android.net.Uri getSelector();
method public long getTicks();
method public int getUnitsPerSecond();
method public int getUnitsPerTick();
@@ -26082,21 +26110,8 @@
method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriScheme(@NonNull String);
}
- public final class TvInteractiveAppInfo implements android.os.Parcelable {
- ctor public TvInteractiveAppInfo(@NonNull android.content.Context, @NonNull android.content.ComponentName);
- method public int describeContents();
- method @NonNull public String getId();
- method @Nullable public android.content.pm.ServiceInfo getServiceInfo();
- method @NonNull public int getSupportedTypes();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.interactive.TvInteractiveAppInfo> CREATOR;
- field public static final int INTERACTIVE_APP_TYPE_ATSC = 2; // 0x2
- field public static final int INTERACTIVE_APP_TYPE_GINGA = 4; // 0x4
- field public static final int INTERACTIVE_APP_TYPE_HBBTV = 1; // 0x1
- }
-
public final class TvInteractiveAppManager {
- method @NonNull public java.util.List<android.media.tv.interactive.TvInteractiveAppInfo> getTvInteractiveAppServiceList();
+ method @NonNull public java.util.List<android.media.tv.interactive.TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList();
method public void prepare(@NonNull String, int);
method public void registerAppLinkInfo(@NonNull String, @NonNull android.media.tv.interactive.AppLinkInfo);
method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppManager.TvInteractiveAppCallback);
@@ -26219,6 +26234,19 @@
method @CallSuper public void setVideoBounds(@NonNull android.graphics.Rect);
}
+ public final class TvInteractiveAppServiceInfo implements android.os.Parcelable {
+ ctor public TvInteractiveAppServiceInfo(@NonNull android.content.Context, @NonNull android.content.ComponentName);
+ method public int describeContents();
+ method @NonNull public String getId();
+ method @Nullable public android.content.pm.ServiceInfo getServiceInfo();
+ method @NonNull public int getSupportedTypes();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.interactive.TvInteractiveAppServiceInfo> CREATOR;
+ field public static final int INTERACTIVE_APP_TYPE_ATSC = 2; // 0x2
+ field public static final int INTERACTIVE_APP_TYPE_GINGA = 4; // 0x4
+ field public static final int INTERACTIVE_APP_TYPE_HBBTV = 1; // 0x1
+ }
+
public class TvInteractiveAppView extends android.view.ViewGroup {
ctor public TvInteractiveAppView(@NonNull android.content.Context);
ctor public TvInteractiveAppView(@NonNull android.content.Context, @Nullable android.util.AttributeSet);
@@ -43786,6 +43814,7 @@
method public int getNetworkTypeBitmask();
method public String getOperatorNumeric();
method public String getPassword();
+ method public int getProfileId();
method public int getProtocol();
method @Deprecated public java.net.InetAddress getProxyAddress();
method public String getProxyAddressAsString();
@@ -43793,6 +43822,7 @@
method public int getRoamingProtocol();
method public String getUser();
method public boolean isEnabled();
+ method public boolean isPersistent();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int AUTH_TYPE_CHAP = 2; // 0x2
field public static final int AUTH_TYPE_NONE = 0; // 0x0
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 3d5232b..d2cc0f5 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -243,7 +243,8 @@
method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public android.telephony.SubscriptionPlan getSubscriptionPlan(@NonNull android.net.NetworkTemplate);
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean);
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderWarningOrLimitReached();
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderLimitReached();
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderWarningReached();
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerNetworkPolicyCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void unregisterNetworkPolicyCallback(@NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 5da1f39..d094f4b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -244,7 +244,6 @@
field public static final String READ_APP_SPECIFIC_LOCALES = "android.permission.READ_APP_SPECIFIC_LOCALES";
field public static final String READ_CARRIER_APP_INFO = "android.permission.READ_CARRIER_APP_INFO";
field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
- field public static final String READ_CLIPBOARD_IN_BACKGROUND = "android.permission.READ_CLIPBOARD_IN_BACKGROUND";
field public static final String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
@@ -1115,6 +1114,7 @@
method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setStrings(@NonNull java.util.Set<android.app.admin.DevicePolicyStringResource>);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setUserProvisioningState(int, @NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification();
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
field public static final String ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE = "android.app.action.BIND_SECONDARY_LOCKSCREEN_SERVICE";
@@ -5490,6 +5490,32 @@
method @NonNull public android.location.GnssCapabilities.Builder setHasSatellitePvt(boolean);
}
+ public final class GnssExcessPathInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @FloatRange(from=0.0f) public float getAttenuationDb();
+ method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
+ method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+ method @NonNull public android.location.GnssReflectingPlane getReflectingPlane();
+ method public boolean hasAttenuation();
+ method public boolean hasExcessPathLength();
+ method public boolean hasExcessPathLengthUncertainty();
+ method public boolean hasReflectingPlane();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssExcessPathInfo> CREATOR;
+ }
+
+ public static final class GnssExcessPathInfo.Builder {
+ ctor public GnssExcessPathInfo.Builder();
+ method @NonNull public android.location.GnssExcessPathInfo build();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder clearAttenuationDb();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthMeters();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthUncertaintyMeters();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setAttenuationDb(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+ }
+
public final class GnssMeasurement implements android.os.Parcelable {
method @Nullable public java.util.Collection<android.location.CorrelationVector> getCorrelationVectors();
method @Nullable public android.location.SatellitePvt getSatellitePvt();
@@ -5571,15 +5597,18 @@
public final class GnssSingleSatCorrection implements android.os.Parcelable {
method public int describeContents();
method @FloatRange(from=0.0f, fromInclusive=false) public float getCarrierFrequencyHz();
+ method @FloatRange(from=0.0f) public float getCombinedAttenuationDb();
method public int getConstellationType();
method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+ method @NonNull public java.util.List<android.location.GnssExcessPathInfo> getGnssExcessPathInfoList();
method @FloatRange(from=0.0f, to=1.0f) public float getProbabilityLineOfSight();
- method @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
+ method @Deprecated @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
method @IntRange(from=0) public int getSatelliteId();
+ method public boolean hasCombinedAttenuation();
method public boolean hasExcessPathLength();
method public boolean hasExcessPathLengthUncertainty();
- method public boolean hasReflectingPlane();
+ method @Deprecated public boolean hasReflectingPlane();
method public boolean hasValidSatelliteLineOfSight();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssSingleSatCorrection> CREATOR;
@@ -5588,15 +5617,18 @@
public static final class GnssSingleSatCorrection.Builder {
ctor public GnssSingleSatCorrection.Builder();
method @NonNull public android.location.GnssSingleSatCorrection build();
+ method @NonNull public android.location.GnssSingleSatCorrection.Builder clearCombinedAttenuationDb();
method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthMeters();
method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthUncertaintyMeters();
method @NonNull public android.location.GnssSingleSatCorrection.Builder clearProbabilityLineOfSight();
method @NonNull public android.location.GnssSingleSatCorrection.Builder setCarrierFrequencyHz(@FloatRange(from=0.0f, fromInclusive=false) float);
+ method @NonNull public android.location.GnssSingleSatCorrection.Builder setCombinedAttenuationDb(@FloatRange(from=0.0f) float);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssSingleSatCorrection.Builder setGnssExcessPathInfoList(@NonNull java.util.List<android.location.GnssExcessPathInfo>);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setProbabilityLineOfSight(@FloatRange(from=0.0f, to=1.0f) float);
- method @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+ method @Deprecated @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setSatelliteId(@IntRange(from=0) int);
}
@@ -10049,9 +10081,9 @@
method @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String);
method @Deprecated @BinderThread public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @Deprecated @BinderThread public void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
- method @BinderThread public void onRevokeOwnPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
method @BinderThread public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String, @NonNull Runnable);
method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
+ method @BinderThread public void onRevokeSelfPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
method @Deprecated @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @BinderThread public void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull android.permission.AdminPermissionControlParams, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
@@ -10865,10 +10897,11 @@
}
public static final class AmbientContextDetectionResult.Builder {
- ctor public AmbientContextDetectionResult.Builder();
+ ctor public AmbientContextDetectionResult.Builder(@NonNull String);
method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder addEvent(@NonNull android.app.ambientcontext.AmbientContextEvent);
+ method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder addEvents(@NonNull java.util.List<android.app.ambientcontext.AmbientContextEvent>);
method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult build();
- method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder setPackageName(@NonNull String);
+ method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder clearEvents();
}
public abstract class AmbientContextDetectionService extends android.app.Service {
@@ -10889,9 +10922,8 @@
}
public static final class AmbientContextDetectionServiceStatus.Builder {
- ctor public AmbientContextDetectionServiceStatus.Builder();
+ ctor public AmbientContextDetectionServiceStatus.Builder(@NonNull String);
method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus build();
- method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus.Builder setPackageName(@NonNull String);
method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus.Builder setStatusCode(int);
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index db95a1f..d984abe 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -300,7 +300,6 @@
}
public class LocaleManager {
- method @Nullable public android.os.LocaleList getSystemLocales();
method public void setSystemLocales(@NonNull android.os.LocaleList);
}
@@ -356,14 +355,8 @@
}
public final class PictureInPictureParams implements android.os.Parcelable {
- method public java.util.List<android.app.RemoteAction> getActions();
- method public float getAspectRatio();
- method @Nullable public android.app.RemoteAction getCloseAction();
- method public float getExpandedAspectRatio();
- method public android.graphics.Rect getSourceRectHint();
- method @Nullable public CharSequence getSubtitle();
- method @Nullable public CharSequence getTitle();
- method public boolean isSeamlessResizeEnabled();
+ method public float getAspectRatioFloat();
+ method public float getExpandedAspectRatioFloat();
}
public final class PictureInPictureUiState implements android.os.Parcelable {
diff --git a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
index 4e6cfb35..f53cfe4 100644
--- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
@@ -169,10 +169,6 @@
mIntroResId = asAttributes.getResourceId(
com.android.internal.R.styleable.AccessibilityShortcutTarget_intro, 0);
asAttributes.recycle();
-
- if ((mDescriptionResId == 0 && mHtmlDescriptionRes == 0) || mSummaryResId == 0) {
- throw new XmlPullParserException("No description or summary in meta-data");
- }
} catch (PackageManager.NameNotFoundException e) {
throw new XmlPullParserException("Unable to create context for: "
+ mActivityInfo.packageName);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f5eb1f6..ac46066 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -77,6 +77,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
+import android.permission.PermissionControllerManager;
import android.permission.PermissionManager;
import android.system.ErrnoException;
import android.system.Os;
@@ -216,6 +217,12 @@
@UnsupportedAppUsage
private @Nullable ClassLoader mClassLoader;
+ /**
+ * The {@link com.android.server.wm.WindowToken} representing this instance if it is
+ * {@link #CONTEXT_TYPE_WINDOW_CONTEXT} or {@link #CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI}.
+ * If the type is {@link #CONTEXT_TYPE_ACTIVITY}, then represents the
+ * {@link android.window.WindowContainerToken} of the activity.
+ */
private final @Nullable IBinder mToken;
private final @NonNull UserHandle mUser;
@@ -2180,8 +2187,9 @@
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
- getSystemService(PermissionManager.class).revokeOwnPermissionsOnKill(permissions);
+ public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
+ getSystemService(PermissionControllerManager.class).revokeSelfPermissionsOnKill(
+ getPackageName(), new ArrayList<String>(permissions));
}
@Override
diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java
index 6f49c9e..a138fa1 100644
--- a/core/java/android/app/GameManager.java
+++ b/core/java/android/app/GameManager.java
@@ -191,7 +191,7 @@
*/
@TestApi
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
- public @GameMode boolean isAngleEnabled(@NonNull String packageName) {
+ public boolean isAngleEnabled(@NonNull String packageName) {
try {
return mService.isAngleEnabled(packageName, mContext.getUserId());
} catch (RemoteException e) {
diff --git a/core/java/android/app/ILocaleManager.aidl b/core/java/android/app/ILocaleManager.aidl
index 348cb2d..3002c8b 100644
--- a/core/java/android/app/ILocaleManager.aidl
+++ b/core/java/android/app/ILocaleManager.aidl
@@ -40,4 +40,9 @@
*/
LocaleList getApplicationLocales(String packageName, int userId);
+ /**
+ * Returns the current system locales.
+ */
+ LocaleList getSystemLocales();
+
}
\ No newline at end of file
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e0c69df..ac979c4 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -393,6 +393,15 @@
}
/**
+ * Resets the {@link #setInTouchMode touch mode} to the device default.
+ */
+ public void resetInTouchMode() {
+ final boolean defaultInTouchMode = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_defaultInTouchMode);
+ setInTouchMode(defaultInTouchMode);
+ }
+
+ /**
* Schedule a callback for when the application's main thread goes idle
* (has no more events to process).
*
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index cedf483e..e9c29b8 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -1103,9 +1103,12 @@
}
/**
- * Registers a listener to execute when the keyguard visibility changes.
+ * Registers a listener to execute when the keyguard locked state changes.
*
- * @param listener The listener to add to receive keyguard visibility changes.
+ * @param listener The listener to add to receive keyguard locked state changes.
+ *
+ * @see #isKeyguardLocked()
+ * @see #removeKeyguardLockedStateListener(KeyguardLockedStateListener)
*/
@RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
public void addKeyguardLockedStateListener(@NonNull @CallbackExecutor Executor executor,
@@ -1124,7 +1127,12 @@
}
/**
- * Unregisters a listener that executes when the keyguard visibility changes.
+ * Unregisters a listener that executes when the keyguard locked state changes.
+ *
+ * @param listener The listener to remove.
+ *
+ * @see #isKeyguardLocked()
+ * @see #addKeyguardLockedStateListener(Executor, KeyguardLockedStateListener)
*/
@RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
public void removeKeyguardLockedStateListener(@NonNull KeyguardLockedStateListener listener) {
diff --git a/core/java/android/app/LocaleManager.java b/core/java/android/app/LocaleManager.java
index 522dc84..efe9e35 100644
--- a/core/java/android/app/LocaleManager.java
+++ b/core/java/android/app/LocaleManager.java
@@ -18,7 +18,6 @@
import android.Manifest;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -127,6 +126,26 @@
}
/**
+ * Returns the current system locales, ignoring app-specific overrides.
+ *
+ * <p><b>Note:</b> Apps should generally access the user's locale preferences as indicated in
+ * their in-process {@link LocaleList}s. However, in case an app-specific locale is set, this
+ * method helps cater to rare use-cases which might require specifically knowing the system
+ * locale.
+ *
+ * <p><b>Note:</b> This API is not user-aware. It returns the system locales for the foreground
+ * user.
+ */
+ @NonNull
+ public LocaleList getSystemLocales() {
+ try {
+ return mService.getSystemLocales();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Sets the current system locales to the provided value.
*
* @hide
@@ -142,19 +161,4 @@
}
}
- /**
- * Returns the current system locales for the device.
- *
- * @hide
- */
- @TestApi
- @Nullable
- public LocaleList getSystemLocales() {
- try {
- return ActivityManager.getService().getConfiguration().getLocales();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
}
diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java
index 2d2788c..3f1844e 100644
--- a/core/java/android/app/PictureInPictureParams.java
+++ b/core/java/android/app/PictureInPictureParams.java
@@ -280,7 +280,7 @@
private Rational mAspectRatio;
/**
- * The expected aspect ratio of the vertically expanded picture-in-picture window.
+ * The expected aspect ratio of the expanded picture-in-picture window.
*/
@Nullable
private Rational mExpandedAspectRatio;
@@ -441,15 +441,21 @@
* @hide
*/
@TestApi
- public float getAspectRatio() {
+ public float getAspectRatioFloat() {
if (mAspectRatio != null) {
return mAspectRatio.floatValue();
}
return 0f;
}
- /** @hide */
- public Rational getAspectRatioRational() {
+ /**
+ * Returns the expected aspect ratio of the picture-in-picture window.
+ *
+ * @return aspect ratio as the desired width / height or {@code null} if not set.
+ * @see PictureInPictureParams.Builder#setAspectRatio(Rational)
+ */
+ @Nullable
+ public Rational getAspectRatio() {
return mAspectRatio;
}
@@ -466,7 +472,7 @@
* @hide
*/
@TestApi
- public float getExpandedAspectRatio() {
+ public float getExpandedAspectRatioFloat() {
if (mExpandedAspectRatio != null) {
return mExpandedAspectRatio.floatValue();
}
@@ -474,6 +480,17 @@
}
/**
+ * Returns the desired aspect ratio of the expanded picture-in-picture window.
+ *
+ * @return aspect ratio as the desired width / height or {@code null} if not set.
+ * @see PictureInPictureParams.Builder#setExpandedAspectRatio(Rational)
+ */
+ @Nullable
+ public Rational getExpandedAspectRatio() {
+ return mExpandedAspectRatio;
+ }
+
+ /**
* @return whether the expanded aspect ratio is set
* @hide
*/
@@ -482,11 +499,17 @@
}
/**
- * @return the set of user actions.
- * @hide
+ * Returns the list of user actions that are associated with the activity when in
+ * picture-in-picture mode.
+ *
+ * @return the user actions in a new list.
+ * @see PictureInPictureParams.Builder#setActions(List)
*/
- @TestApi
+ @NonNull
public List<RemoteAction> getActions() {
+ if (mUserActions == null) {
+ return new ArrayList<>();
+ }
return mUserActions;
}
@@ -499,10 +522,11 @@
}
/**
- * @return the close action.
- * @hide
+ * Returns the action that is to replace the system close action.
+ *
+ * @return the close action or {@code null} if not set.
+ * @see PictureInPictureParams.Builder#setCloseAction(RemoteAction)
*/
- @TestApi
@Nullable
public RemoteAction getCloseAction() {
return mCloseAction;
@@ -528,10 +552,12 @@
}
/**
- * @return the source rect hint
- * @hide
+ * Returns the source rect hint.
+ *
+ * @return the source rect hint also known as launch bounds or {@code null} if not set.
+ * @see PictureInPictureParams.Builder#setSourceRectHint(Rect)
*/
- @TestApi
+ @Nullable
public Rect getSourceRectHint() {
return mSourceRectHint;
}
@@ -545,18 +571,23 @@
}
/**
- * @return whether auto pip is enabled.
- * @hide
+ * Returns whether auto enter picture-in-picture is enabled.
+ *
+ * @return {@code true} if the system will automatically put the activity in
+ * picture-in-picture mode.
+ * @see PictureInPictureParams.Builder#setAutoEnterEnabled(boolean)
*/
public boolean isAutoEnterEnabled() {
return mAutoEnterEnabled == null ? false : mAutoEnterEnabled;
}
/**
- * @return whether seamless resize is enabled.
- * @hide
+ * Returns whether seamless resize is enabled.
+ *
+ * @return true if the system can seamlessly resize the window while activity is in
+ * picture-in-picture mode.
+ * @see PictureInPictureParams.Builder#setSeamlessResizeEnabled(boolean)
*/
- @TestApi
public boolean isSeamlessResizeEnabled() {
return mSeamlessResizeEnabled == null ? true : mSeamlessResizeEnabled;
}
@@ -570,10 +601,11 @@
}
/**
- * @return title of the pip.
- * @hide
+ * Returns the title of the picture-in-picture window that may be displayed to the user.
+ *
+ * @return title of the picture-in-picture window.
+ * @see PictureInPictureParams.Builder#setTitle(CharSequence)
*/
- @TestApi
@Nullable
public CharSequence getTitle() {
return mTitle;
@@ -588,10 +620,11 @@
}
/**
- * @return subtitle of the pip.
- * @hide
+ * Returns the subtitle of the picture-in-picture window that may be displayed to the user.
+ *
+ * @return subtitle of the picture-in-picture window.
+ * @see PictureInPictureParams.Builder#setSubtitle(CharSequence)
*/
- @TestApi
@Nullable
public CharSequence getSubtitle() {
return mSubtitle;
@@ -716,7 +749,7 @@
@Override
public String toString() {
return "PictureInPictureParams("
- + " aspectRatio=" + getAspectRatioRational()
+ + " aspectRatio=" + getAspectRatio()
+ " expandedAspectRatio=" + mExpandedAspectRatio
+ " sourceRectHint=" + getSourceRectHint()
+ " hasSetActions=" + hasSetActions()
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 150888c..89854bb 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -24,9 +24,6 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
-import android.app.compat.CompatChanges;
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -42,7 +39,6 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.UserHandle;
import android.util.Pair;
import android.util.Slog;
import android.view.View;
@@ -524,27 +520,6 @@
private final Map<NearbyMediaDevicesProvider, NearbyMediaDevicesProviderWrapper>
nearbyMediaDevicesProviderMap = new HashMap<>();
- /**
- * Media controls based on {@link android.app.Notification.MediaStyle} notifications will have
- * actions based on the media session's {@link android.media.session.PlaybackState}, rather than
- * the notification's actions.
- *
- * These actions will be:
- * - Play/Pause (depending on whether the current state is a playing state)
- * - Previous (if declared), or a custom action if the slot is not reserved with
- * {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV}
- * - Next (if declared), or a custom action if the slot is not reserved with
- * {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT}
- * - Custom action
- * - Custom action
- *
- * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
- * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
- */
- @ChangeId
- @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
- private static final long MEDIA_CONTROL_SESSION_ACTIONS = 203800354L;
-
@UnsupportedAppUsage
private Context mContext;
private IStatusBarService mService;
@@ -1152,20 +1127,6 @@
}
}
- /**
- * Checks whether the given package should use session-based actions for its media controls.
- *
- * @param packageName App posting media controls
- * @param userId Current user ID
- * @return true if the app supports session actions
- *
- * @hide
- */
- public static boolean useMediaSessionActionsForApp(String packageName, int userId) {
- UserHandle handle = UserHandle.getUserHandleForUid(userId);
- return CompatChanges.isChangeEnabled(MEDIA_CONTROL_SESSION_ACTIONS, packageName, handle);
- }
-
/** @hide */
public static String windowStateToString(int state) {
if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING";
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 27fe312..7269b0d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -15765,4 +15765,23 @@
}
return deviceManagerConfig;
}
+
+ /**
+ * @return {@code true} if bypassing the device policy management role qualification is allowed
+ * with the current state of the device.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS)
+ public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
+ if (mService != null) {
+ try {
+ return mService.shouldAllowBypassingDevicePolicyManagementRoleQualification();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
}
diff --git a/core/java/android/app/admin/FactoryResetProtectionPolicy.java b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
index 40ae1f0..7e95177 100644
--- a/core/java/android/app/admin/FactoryResetProtectionPolicy.java
+++ b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
@@ -25,6 +25,7 @@
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
@@ -254,4 +255,18 @@
return !mFactoryResetProtectionAccounts.isEmpty() && mFactoryResetProtectionEnabled;
}
+ /**
+ * @hide
+ */
+ public void dump(IndentingPrintWriter pw) {
+ pw.print("factoryResetProtectionEnabled=");
+ pw.println(mFactoryResetProtectionEnabled);
+
+ pw.print("factoryResetProtectionAccounts=");
+ pw.increaseIndent();
+ for (int i = 0; i < mFactoryResetProtectionAccounts.size(); i++) {
+ pw.println(mFactoryResetProtectionAccounts.get(i));
+ }
+ pw.decreaseIndent();
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 77db146..fb1ca41 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -558,4 +558,6 @@
void setStrings(in List<DevicePolicyStringResource> strings);
void resetStrings(in String[] stringIds);
ParcelableResource getString(String stringId);
+
+ boolean shouldAllowBypassingDevicePolicyManagementRoleQualification();
}
diff --git a/core/java/android/app/usage/BroadcastResponseStats.java b/core/java/android/app/usage/BroadcastResponseStats.java
index e1d37e1..572c453 100644
--- a/core/java/android/app/usage/BroadcastResponseStats.java
+++ b/core/java/android/app/usage/BroadcastResponseStats.java
@@ -29,6 +29,8 @@
* Class containing a collection of stats related to response events started from an app
* after receiving a broadcast.
*
+ * @see UsageStatsManager#queryBroadcastResponseStats(String, long)
+ * @see UsageStatsManager#clearBroadcastResponseStats(String, long)
* @hide
*/
@SystemApi
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 60efb4d..24b1b6a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -6508,22 +6508,22 @@
/**
- * Triggers the asynchronous revocation of a permission.
+ * Triggers the asynchronous revocation of a runtime permission. If the permission is not
+ * currently granted, nothing happens (even if later granted by the user).
*
* @param permName The name of the permission to be revoked.
- * @see #revokeOwnPermissionsOnKill(Collection)
+ * @see #revokeSelfPermissionsOnKill(Collection)
+ * @throws IllegalArgumentException if the permission is not a runtime permission
*/
- public void revokeOwnPermissionOnKill(@NonNull String permName) {
- revokeOwnPermissionsOnKill(Collections.singletonList(permName));
+ public void revokeSelfPermissionOnKill(@NonNull String permName) {
+ revokeSelfPermissionsOnKill(Collections.singletonList(permName));
}
/**
* Triggers the revocation of one or more permissions for the calling package. A package is only
- * able to revoke a permission under the following conditions:
- * <ul>
- * <li>Each permission in {@code permissions} must be granted to the calling package.
- * <li>Each permission in {@code permissions} must be a runtime permission.
- * </ul>
+ * able to revoke runtime permissions. If a permission is not currently granted, it is ignored
+ * and will not get revoked (even if later granted by the user). Ultimately, you should never
+ * make assumptions about a permission status as users may grant or revoke them at any time.
* <p>
* Background permissions which have no corresponding foreground permission still granted once
* the revocation is effective will also be revoked.
@@ -6549,8 +6549,9 @@
* @param permissions Collection of permissions to be revoked.
* @see PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)
* @see PackageManager#getPlatformPermissionsForGroup(String, Executor, Consumer)
+ * @throws IllegalArgumentException if any of the permissions is not a runtime permission
*/
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
+ public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
throw new AbstractMethodError("Must be overridden in implementing class");
}
@@ -7145,8 +7146,9 @@
}
/**
- * Returns token if the {@link Context} is a {@link android.app.WindowContext}. Returns
- * {@code null} otherwise.
+ * Returns the {@link IBinder} representing the associated
+ * {@link com.android.server.wm.WindowToken} if the {@link Context} is a
+ * {@link android.app.WindowContext}. Returns {@code null} otherwise.
*
* @hide
*/
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 9adf173..4ecd776 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1036,8 +1036,8 @@
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
- mBase.revokeOwnPermissionsOnKill(permissions);
+ public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
+ mBase.revokeSelfPermissionsOnKill(permissions);
}
@Override
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 478befd..2c207bc 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -8903,8 +8903,12 @@
* @return the value of an item previously added with putExtra(),
* or null if no Parcelable value was found.
*
+ * @deprecated Use the type-safer {@link #getParcelableExtra(String, Class)} starting from
+ * Android {@link Build.VERSION_CODES#TIRAMISU}.
+ *
* @see #putExtra(String, Parcelable)
*/
+ @Deprecated
public @Nullable <T extends Parcelable> T getParcelableExtra(String name) {
return mExtras == null ? null : mExtras.<T>getParcelable(name);
}
@@ -8913,12 +8917,31 @@
* Retrieve extended data from the intent.
*
* @param name The name of the desired item.
+ * @param clazz The type of the object expected.
+ *
+ * @return the value of an item previously added with putExtra(),
+ * or null if no Parcelable value was found.
+ *
+ * @see #putExtra(String, Parcelable)
+ */
+ public @Nullable <T> T getParcelableExtra(@Nullable String name, @NonNull Class<T> clazz) {
+ return mExtras == null ? null : mExtras.getParcelable(name, clazz);
+ }
+
+ /**
+ * Retrieve extended data from the intent.
+ *
+ * @param name The name of the desired item.
*
* @return the value of an item previously added with putExtra(),
* or null if no Parcelable[] value was found.
*
+ * @deprecated Use the type-safer {@link #getParcelableArrayExtra(String, Class)} starting from
+ * Android {@link Build.VERSION_CODES#TIRAMISU}.
+ *
* @see #putExtra(String, Parcelable[])
*/
+ @Deprecated
public @Nullable Parcelable[] getParcelableArrayExtra(String name) {
return mExtras == null ? null : mExtras.getParcelableArray(name);
}
@@ -8927,13 +8950,34 @@
* Retrieve extended data from the intent.
*
* @param name The name of the desired item.
+ * @param clazz The type of the items inside the array. This is only verified when unparceling.
+ *
+ * @return the value of an item previously added with putExtra(),
+ * or null if no Parcelable[] value was found.
+ *
+ * @see #putExtra(String, Parcelable[])
+ */
+ @SuppressLint({"ArrayReturn", "NullableCollection"})
+ public @Nullable <T> T[] getParcelableArrayExtra(@Nullable String name,
+ @NonNull Class<T> clazz) {
+ return mExtras == null ? null : mExtras.getParcelableArray(name, clazz);
+ }
+
+ /**
+ * Retrieve extended data from the intent.
+ *
+ * @param name The name of the desired item.
*
* @return the value of an item previously added with
* putParcelableArrayListExtra(), or null if no
* ArrayList<Parcelable> value was found.
*
+ * @deprecated Use the type-safer {@link #getParcelableArrayListExtra(String, Class)} starting
+ * from Android {@link Build.VERSION_CODES#TIRAMISU}.
+ *
* @see #putParcelableArrayListExtra(String, ArrayList)
*/
+ @Deprecated
public @Nullable <T extends Parcelable> ArrayList<T> getParcelableArrayListExtra(String name) {
return mExtras == null ? null : mExtras.<T>getParcelableArrayList(name);
}
@@ -8942,10 +8986,32 @@
* Retrieve extended data from the intent.
*
* @param name The name of the desired item.
+ * @param clazz The type of the items inside the array list. This is only verified when
+ * unparceling.
+ *
+ * @return the value of an item previously added with
+ * putParcelableArrayListExtra(), or null if no
+ * ArrayList<Parcelable> value was found.
+ *
+ * @see #putParcelableArrayListExtra(String, ArrayList)
+ */
+ @SuppressLint({"ConcreteCollection", "NullableCollection"})
+ public @Nullable <T> ArrayList<T> getParcelableArrayListExtra(@Nullable String name,
+ @NonNull Class<? extends T> clazz) {
+ return mExtras == null ? null : mExtras.<T>getParcelableArrayList(name, clazz);
+ }
+
+ /**
+ * Retrieve extended data from the intent.
+ *
+ * @param name The name of the desired item.
*
* @return the value of an item previously added with putExtra(),
* or null if no Serializable value was found.
*
+ * @deprecated Use the type-safer {@link #getSerializableExtra(String, Class)} starting from
+ * Android {@link Build.VERSION_CODES#TIRAMISU}.
+ *
* @see #putExtra(String, Serializable)
*/
public @Nullable Serializable getSerializableExtra(String name) {
@@ -8956,6 +9022,22 @@
* Retrieve extended data from the intent.
*
* @param name The name of the desired item.
+ * @param clazz The type of the object expected.
+ *
+ * @return the value of an item previously added with putExtra(),
+ * or null if no Serializable value was found.
+ *
+ * @see #putExtra(String, Serializable)
+ */
+ public @Nullable <T extends Serializable> T getSerializableExtra(@Nullable String name,
+ @NonNull Class<T> clazz) {
+ return mExtras == null ? null : mExtras.getSerializable(name, clazz);
+ }
+
+ /**
+ * Retrieve extended data from the intent.
+ *
+ * @param name The name of the desired item.
*
* @return the value of an item previously added with
* putIntegerArrayListExtra(), or null if no
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index a05f5c9..c8bbb0c1 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -79,6 +79,13 @@
@GuardedBy("sSync") private static ArraySet<ApkAssets> sSystemApkAssetsSet;
/**
+ * Cookie value to use when the actual cookie is unknown. This value tells the system to search
+ * all the ApkAssets for the asset.
+ * @hide
+ */
+ public static final int COOKIE_UNKNOWN = -1;
+
+ /**
* Mode for {@link #open(String, int)}: no specific information about how
* data will be accessed.
*/
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 0f9075b..03d1151 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -294,8 +294,8 @@
dest.setTouchableInsets(
ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- // TODO(b/205803355): See if we can use View#OnLayoutChangeListener().
- // TODO(b/205803355): See if we can replace DecorView#mNavigationColorViewState.view
+ // TODO(b/215443343): See if we can use View#OnLayoutChangeListener().
+ // TODO(b/215443343): See if we can replace DecorView#mNavigationColorViewState.view
boolean zOrderChanged = false;
if (decor instanceof ViewGroup) {
ViewGroup decorGroup = (ViewGroup) decor;
diff --git a/core/java/android/inputmethodservice/navigationbar/DeadZone.java b/core/java/android/inputmethodservice/navigationbar/DeadZone.java
index 4cfd813..382b6b0 100644
--- a/core/java/android/inputmethodservice/navigationbar/DeadZone.java
+++ b/core/java/android/inputmethodservice/navigationbar/DeadZone.java
@@ -148,7 +148,7 @@
if (DEBUG) {
Log.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
}
- //TODO(b/205803355): call mNavBarController.touchAutoDim(mDisplayId); here
+ //TODO(b/215443343): call mNavBarController.touchAutoDim(mDisplayId); here
int size = (int) getSize(event.getEventTime());
// In the vertical orientation consume taps along the left edge.
// In horizontal orientation consume taps along the top edge.
diff --git a/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java b/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
index cfdb6ca..92d358f 100644
--- a/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
+++ b/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
@@ -89,7 +89,7 @@
public KeyButtonView(Context context, AttributeSet attrs) {
super(context, attrs);
- // TODO(b/205803355): Figure out better place to set this.
+ // TODO(b/215443343): Figure out better place to set this.
switch (getId()) {
case com.android.internal.R.id.input_method_nav_back:
mCode = KEYCODE_BACK;
@@ -285,11 +285,11 @@
private void sendEvent(int action, int flags, long when) {
if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
if (action == MotionEvent.ACTION_UP) {
- // TODO(b/205803355): Implement notifyBackAction();
+ // TODO(b/215443343): Implement notifyBackAction();
}
}
- // TODO(b/205803355): Consolidate this logic to somewhere else.
+ // TODO(b/215443343): Consolidate this logic to somewhere else.
if (mContext instanceof InputMethodService) {
final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 18ec8f5..2c2a703 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -580,6 +580,24 @@
}
/**
+ * Notifies that the specified {@link NetworkStatsProvider} has reached its warning threshold
+ * which was set through {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}.
+ *
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK})
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void notifyStatsProviderWarningReached() {
+ try {
+ mService.notifyStatsProviderWarningOrLimitReached();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Notifies that the specified {@link NetworkStatsProvider} has reached its quota
* which was set through {@link NetworkStatsProvider#onSetLimit(String, long)} or
* {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}.
@@ -590,7 +608,7 @@
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public void notifyStatsProviderWarningOrLimitReached() {
+ public void notifyStatsProviderLimitReached() {
try {
mService.notifyStatsProviderWarningOrLimitReached();
} catch (RemoteException e) {
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index c9dd06c..e3f02e7 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -59,6 +59,6 @@
void getHibernationEligibility(
in String packageName,
in AndroidFuture callback);
- void revokeOwnPermissionsOnKill(in String packageName, in List<String> permissions,
+ void revokeSelfPermissionsOnKill(in String packageName, in List<String> permissions,
in AndroidFuture callback);
}
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 619c870..6a93b35 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -76,8 +76,6 @@
List<SplitPermissionInfoParcelable> getSplitPermissions();
- void revokeOwnPermissionsOnKill(String packageName, in List<String> permissions);
-
void startOneTimePermissionSession(String packageName, int userId, long timeout,
long revokeAfterKilledDelay, int importanceToResetTimer,
int importanceToKeepSessionAlive);
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index a005ab4e..3c2c7f0 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -916,15 +916,15 @@
* @param packageName The name of the package for which the permissions will be revoked.
* @param permissions List of permissions to be revoked.
*
- * @see Context#revokeOwnPermissionsOnKill(java.util.Collection)
+ * @see Context#revokeSelfPermissionsOnKill(java.util.Collection)
*
* @hide
*/
- public void revokeOwnPermissionsOnKill(@NonNull String packageName,
+ public void revokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions) {
mRemoteService.postAsync(service -> {
AndroidFuture<Void> callback = new AndroidFuture<>();
- service.revokeOwnPermissionsOnKill(packageName, permissions, callback);
+ service.revokeSelfPermissionsOnKill(packageName, permissions, callback);
return callback;
}).whenComplete((result, err) -> {
if (err != null) {
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 3292e71..4efffc5a 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -40,6 +40,7 @@
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -339,10 +340,10 @@
* @param permissions List of permissions to be revoked.
* @param callback Callback waiting for operation to be complete.
*
- * @see PermissionManager#revokeOwnPermissionsOnKill(java.util.Collection)
+ * @see android.content.Context#revokeSelfPermissionsOnKill(java.util.Collection)
*/
@BinderThread
- public void onRevokeOwnPermissionsOnKill(@NonNull String packageName,
+ public void onRevokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull Runnable callback) {
throw new AbstractMethodError("Must be overridden in implementing class");
}
@@ -703,13 +704,19 @@
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull String packageName,
+ public void revokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull AndroidFuture callback) {
try {
- enforceSomePermissionsGrantedToCaller(
- Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
Objects.requireNonNull(callback);
- onRevokeOwnPermissionsOnKill(packageName, permissions,
+
+ final int callingUid = Binder.getCallingUid();
+ int targetPackageUid = getPackageManager().getPackageUid(packageName,
+ PackageManager.PackageInfoFlags.of(0));
+ if (targetPackageUid != callingUid) {
+ enforceSomePermissionsGrantedToCaller(
+ Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
+ }
+ onRevokeSelfPermissionsOnKill(packageName, permissions,
() -> callback.complete(null));
} catch (Throwable t) {
callback.completeExceptionally(t);
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index c509de6..7a797ce 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -76,7 +76,6 @@
import com.android.internal.util.CollectionUtils;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -626,19 +625,6 @@
}
/**
- * @see Context#revokeOwnPermissionsOnKill(Collection)
- * @hide
- */
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
- try {
- mPermissionManager.revokeOwnPermissionsOnKill(mContext.getPackageName(),
- new ArrayList<String>(permissions));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Gets the state flags associated with a permission.
*
* @param packageName the package name for which to get the flags
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
index 227194e..a216ed5 100644
--- a/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
@@ -26,6 +26,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Represents a {@code AmbientContextEvent} detection result reported by the detection service.
@@ -127,7 +128,9 @@
private @NonNull String mPackageName;
private long mBuilderFieldsSet = 0L;
- public Builder() {
+ public Builder(@NonNull String packageName) {
+ Objects.requireNonNull(packageName);
+ mPackageName = packageName;
}
/**
@@ -144,26 +147,37 @@
}
/**
- * The package to deliver the response to.
+ * Adds a list of events to the builder.
*/
- public @NonNull Builder setPackageName(@NonNull String value) {
+ public @NonNull Builder addEvents(@NonNull List<AmbientContextEvent> values) {
checkNotUsed();
- mBuilderFieldsSet |= 0x2;
- mPackageName = value;
+ if (mEvents == null) {
+ mBuilderFieldsSet |= 0x1;
+ mEvents = new ArrayList<>();
+ }
+ mEvents.addAll(values);
+ return this;
+ }
+
+ /**
+ * Clears all events from the builder.
+ */
+ public @NonNull Builder clearEvents() {
+ checkNotUsed();
+ if (mEvents != null) {
+ mEvents.clear();
+ }
return this;
}
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull AmbientContextDetectionResult build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x4; // Mark builder used
+ mBuilderFieldsSet |= 0x2; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mEvents = new ArrayList<>();
}
- if ((mBuilderFieldsSet & 0x2) == 0) {
- mPackageName = "";
- }
AmbientContextDetectionResult o = new AmbientContextDetectionResult(
mEvents,
mPackageName);
@@ -171,7 +185,7 @@
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x4) != 0) {
+ if ((mBuilderFieldsSet & 0x2) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionService.java b/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
index 6224aa1..8cf3411 100644
--- a/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
@@ -134,12 +134,18 @@
}
/**
- * Starts detection and provides detected events to the statusConsumer. The ongoing detection
- * will keep running, until onStopDetection is called. If there were previously requested
- * detection from the same package, the previous request will be replaced with the new request.
- * The implementation should keep track of whether the user consented each requested
- * AmbientContextEvent for the app. If not consented, the statusConsumer should get a response
- * with STATUS_ACCESS_DENIED.
+ * Called when a client app requests starting detection of the events in the request. The
+ * implementation should keep track of whether the user has explicitly consented to detecting
+ * the events using on-going ambient sensor (e.g. microphone), and agreed to share the
+ * detection results with this client app. If the user has not consented, the detection
+ * should not start, and the statusConsumer should get a response with STATUS_ACCESS_DENIED.
+ * If the user has made the consent and the underlying services are available, the
+ * implementation should start detection and provide detected events to the
+ * detectionResultConsumer. If the type of event needs immediate attention, the implementation
+ * should send result as soon as detected. Otherwise, the implementation can bulk send response.
+ * The ongoing detection will keep running, until onStopDetection is called. If there were
+ * previously requested detection from the same package, regardless of the type of events in
+ * the request, the previous request will be replaced with the new request.
*
* @param request The request with events to detect.
* @param packageName the requesting app's package name
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
index 3e92f39..199e674 100644
--- a/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
@@ -24,6 +24,8 @@
import com.android.internal.util.AnnotationValidations;
+import java.util.Objects;
+
/**
* Represents a status for the {@code AmbientContextDetectionService}.
*
@@ -121,7 +123,9 @@
private @NonNull String mPackageName;
private long mBuilderFieldsSet = 0L;
- public Builder() {
+ public Builder(@NonNull String packageName) {
+ Objects.requireNonNull(packageName);
+ mPackageName = packageName;
}
/**
@@ -134,27 +138,14 @@
return this;
}
- /**
- * The package to deliver the response to.
- */
- public @NonNull Builder setPackageName(@NonNull String value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x2;
- mPackageName = value;
- return this;
- }
-
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull AmbientContextDetectionServiceStatus build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x4; // Mark builder used
+ mBuilderFieldsSet |= 0x2; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mStatusCode = AmbientContextManager.STATUS_UNKNOWN;
}
- if ((mBuilderFieldsSet & 0x2) == 0) {
- mPackageName = "";
- }
AmbientContextDetectionServiceStatus o = new AmbientContextDetectionServiceStatus(
mStatusCode,
mPackageName);
@@ -162,7 +153,7 @@
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x4) != 0) {
+ if ((mBuilderFieldsSet & 0x2) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 34e7ea7..fe6ae78 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -96,7 +96,7 @@
DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "true");
DEFAULT_FLAGS.put(SETTINGS_SUPPORT_LARGE_SCREEN, "true");
DEFAULT_FLAGS.put("settings_search_always_expand", "true");
- DEFAULT_FLAGS.put(SETTINGS_APP_LANGUAGE_SELECTION, "false");
+ DEFAULT_FLAGS.put(SETTINGS_APP_LANGUAGE_SELECTION, "true");
DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true");
DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "false");
DEFAULT_FLAGS.put(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE, "true");
diff --git a/core/java/android/util/TimingsTraceLog.java b/core/java/android/util/TimingsTraceLog.java
index 066709f..48a5cea 100644
--- a/core/java/android/util/TimingsTraceLog.java
+++ b/core/java/android/util/TimingsTraceLog.java
@@ -147,7 +147,7 @@
* Logs a duration so it can be parsed by external tools for performance reporting.
*/
public void logDuration(String name, long timeMs) {
- Slog.d(mTag, name + " took to complete: " + timeMs + "ms");
+ Slog.v(mTag, name + " took to complete: " + timeMs + "ms");
}
/**
diff --git a/core/java/android/view/ContentRecordingSession.java b/core/java/android/view/ContentRecordingSession.java
index db4ec11..c66c70af 100644
--- a/core/java/android/view/ContentRecordingSession.java
+++ b/core/java/android/view/ContentRecordingSession.java
@@ -66,10 +66,11 @@
private int mContentToRecord = RECORD_CONTENT_DISPLAY;
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@VisibleForTesting
@Nullable
@@ -192,10 +193,11 @@
}
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * {The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@DataClass.Generated.Member
public @VisibleForTesting @Nullable IBinder getTokenToRecord() {
@@ -231,10 +233,11 @@
}
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * {The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@DataClass.Generated.Member
public @NonNull ContentRecordingSession setTokenToRecord(@VisibleForTesting @NonNull IBinder value) {
@@ -390,10 +393,11 @@
}
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * {The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@DataClass.Generated.Member
public @NonNull Builder setTokenToRecord(@VisibleForTesting @NonNull IBinder value) {
@@ -433,7 +437,7 @@
}
@DataClass.Generated(
- time = 1644843382972L,
+ time = 1645803878639L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/ContentRecordingSession.java",
inputSignatures = "public static final int RECORD_CONTENT_DISPLAY\npublic static final int RECORD_CONTENT_TASK\nprivate int mDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate @com.android.internal.annotations.VisibleForTesting @android.annotation.Nullable android.os.IBinder mTokenToRecord\npublic static android.view.ContentRecordingSession createDisplaySession(android.os.IBinder)\npublic static android.view.ContentRecordingSession createTaskSession(android.os.IBinder)\npublic static boolean isValid(android.view.ContentRecordingSession)\npublic static boolean isSameDisplay(android.view.ContentRecordingSession,android.view.ContentRecordingSession)\nclass ContentRecordingSession extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genSetters=true, genEqualsHashCode=true)")
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 190adbd..61098d6 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -55,10 +55,10 @@
*/
private final int mTouchSlop;
/**
- * The timeout used to distinguish tap from handwriting. If the stylus doesn't move before this
- * timeout, it's not considered as handwriting.
+ * The timeout used to distinguish tap or long click from handwriting. If the stylus doesn't
+ * move before this timeout, it's not considered as handwriting.
*/
- private final long mTapTimeoutInMillis;
+ private final long mHandwritingTimeoutInMillis;
private State mState = new State();
private final HandwritingAreaTracker mHandwritingAreasTracker = new HandwritingAreaTracker();
@@ -90,7 +90,7 @@
public HandwritingInitiator(@NonNull ViewConfiguration viewConfiguration,
@NonNull InputMethodManager inputMethodManager) {
mTouchSlop = viewConfiguration.getScaledTouchSlop();
- mTapTimeoutInMillis = ViewConfiguration.getTapTimeout();
+ mHandwritingTimeoutInMillis = ViewConfiguration.getLongPressTimeout();
mImm = inputMethodManager;
}
@@ -145,7 +145,7 @@
final long timeElapsed =
motionEvent.getEventTime() - mState.mStylusDownTimeInMillis;
- if (timeElapsed > mTapTimeoutInMillis) {
+ if (timeElapsed > mHandwritingTimeoutInMillis) {
reset();
return;
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 64f5668..f3c65ea 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -64,6 +64,7 @@
import android.view.Surface.OutOfResourcesException;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.VirtualRefBasePtr;
import dalvik.system.CloseGuard;
@@ -2961,6 +2962,8 @@
@NonNull
public Transaction setScale(@NonNull SurfaceControl sc, float scaleX, float scaleY) {
checkPreconditions(sc);
+ Preconditions.checkArgument(scaleX >= 0, "Negative value passed in for scaleX");
+ Preconditions.checkArgument(scaleY >= 0, "Negative value passed in for scaleY");
nativeSetScale(mNativeObject, sc.mNativeObject, scaleX, scaleY);
return this;
}
@@ -3205,6 +3208,7 @@
public @NonNull Transaction setCrop(@NonNull SurfaceControl sc, @Nullable Rect crop) {
checkPreconditions(sc);
if (crop != null) {
+ Preconditions.checkArgument(crop.isValid(), "Crop isn't valid.");
nativeSetWindowCrop(mNativeObject, sc.mNativeObject,
crop.left, crop.top, crop.right, crop.bottom);
} else {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index cdbf8b4..b72725a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3165,11 +3165,8 @@
// possible that checking the most recent value is actually more
// correct here.
if (!mStopped || wasReportNextDraw) {
- boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
- (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
- if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
- || mHeight != host.getMeasuredHeight() || dispatchApplyInsets ||
- updatedConfiguration) {
+ if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()
+ || dispatchApplyInsets || updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width,
lp.privateFlags);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height,
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 2dc5fbd..b0da877 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -60,47 +60,41 @@
private static boolean sUseBLASTAdapter = false;
/**
- * The user is navigating with keys (not the touch screen), so
- * navigational focus should be shown.
- */
- public static final int RELAYOUT_RES_IN_TOUCH_MODE = 0x1;
-
- /**
* This is the first time the window is being drawn,
* so the client must call drawingFinished() when done
*/
- public static final int RELAYOUT_RES_FIRST_TIME = 0x2;
+ public static final int RELAYOUT_RES_FIRST_TIME = 1;
/**
* The window manager has changed the surface from the last call.
*/
- public static final int RELAYOUT_RES_SURFACE_CHANGED = 0x4;
+ public static final int RELAYOUT_RES_SURFACE_CHANGED = 1 << 1;
/**
* The window is being resized by dragging on the docked divider. The client should render
* at (0, 0) and extend its background to the background frame passed into
* {@link IWindow#resized}.
*/
- public static final int RELAYOUT_RES_DRAG_RESIZING_DOCKED = 0x8;
+ public static final int RELAYOUT_RES_DRAG_RESIZING_DOCKED = 1 << 2;
/**
* The window is being resized by dragging one of the window corners,
* in this case the surface would be fullscreen-sized. The client should
* render to the actual frame location (instead of (0,curScrollY)).
*/
- public static final int RELAYOUT_RES_DRAG_RESIZING_FREEFORM = 0x10;
+ public static final int RELAYOUT_RES_DRAG_RESIZING_FREEFORM = 1 << 3;
/**
* The window manager has changed the size of the surface from the last call.
*/
- public static final int RELAYOUT_RES_SURFACE_RESIZED = 0x20;
+ public static final int RELAYOUT_RES_SURFACE_RESIZED = 1 << 4;
/**
* In multi-window we force show the system bars. Because we don't want that the surface size
* changes in this mode, we instead have a flag whether the system bar sizes should always be
* consumed, so the app is treated like there is no virtual system bars at all.
*/
- public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 0x40;
+ public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 1 << 5;
/**
* This flag indicates the client should not directly submit it's next frame,
@@ -108,7 +102,7 @@
* {@link WindowManagerService#finishDrawing}. This is used by the WM
* BLASTSyncEngine to synchronize rendering of multiple windows.
*/
- public static final int RELAYOUT_RES_BLAST_SYNC = 0x80;
+ public static final int RELAYOUT_RES_BLAST_SYNC = 1 << 6;
/**
* Flag for relayout: the client will be later giving
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index ad151df..06588b2 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -332,8 +332,7 @@
outInsetsState.set(mInsetsState);
}
- // Include whether the window is in touch mode.
- return isInTouchMode() ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
+ return 0;
}
@Override
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 34c47ed..06bc4b5 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -33,6 +33,7 @@
import android.graphics.HardwareRendererObserver;
import android.os.Handler;
import android.os.Trace;
+import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.Choreographer;
@@ -188,6 +189,7 @@
if (mBeginVsyncId != INVALID_ID) {
mSurfaceControlWrapper.addJankStatsListener(
FrameTracker.this, mSurfaceControl);
+ markEvent("FT#deferMonitoring");
postTraceStartMarker();
}
}
@@ -241,8 +243,9 @@
}
if (mSurfaceControl != null) {
if (mDeferMonitoring) {
+ markEvent("FT#deferMonitoring");
// Normal case, we begin the instrument from the very beginning,
- // except the first frame.
+ // will exclude the first frame.
postTraceStartMarker();
} else {
// If we don't begin the instrument from the very beginning,
@@ -272,6 +275,7 @@
return;
}
mTracingStarted = true;
+ markEvent("FT#begin");
Trace.beginAsyncSection(mSession.getName(), (int) mBeginVsyncId);
}
}
@@ -295,6 +299,7 @@
Log.d(TAG, "end: " + mSession.getName()
+ ", end=" + mEndVsyncId + ", reason=" + reason);
}
+ markEvent("FT#end#" + reason);
Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
mSession.setReason(reason);
@@ -322,6 +327,7 @@
reason == REASON_CANCEL_NOT_BEGUN || reason == REASON_CANCEL_SAME_VSYNC;
if (mCancelled || (mEndVsyncId != INVALID_ID && !cancelFromEnd)) return false;
mCancelled = true;
+ markEvent("FT#cancel#" + reason);
// We don't need to end the trace section if it never begun.
if (mTracingStarted) {
Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
@@ -343,6 +349,11 @@
}
}
+ private void markEvent(String desc) {
+ Trace.beginSection(TextUtils.formatSimple("%s#%s", mSession.getName(), desc));
+ Trace.endSection();
+ }
+
private void notifyCujEvent(String action) {
if (mListener == null) return;
mListener.onCujEvents(mSession, action);
diff --git a/core/java/com/android/internal/os/KernelAllocationStats.java b/core/java/com/android/internal/os/KernelAllocationStats.java
index 1c3f8b0..58d51e3 100644
--- a/core/java/com/android/internal/os/KernelAllocationStats.java
+++ b/core/java/com/android/internal/os/KernelAllocationStats.java
@@ -24,21 +24,29 @@
/** Process dma-buf stats. */
public static final class ProcessDmabuf {
+ public final int uid;
+ public final String processName;
+ public final int oomScore;
+
/** Size of buffers retained by the process. */
public final int retainedSizeKb;
/** Number of buffers retained by the process. */
public final int retainedBuffersCount;
- /** Size of buffers mapped to the address space. */
- public final int mappedSizeKb;
- /** Count of buffers mapped to the address space. */
- public final int mappedBuffersCount;
+ /** Size of buffers shared with Surface Flinger. */
+ public final int surfaceFlingerSizeKb;
+ /** Count of buffers shared with Surface Flinger. */
+ public final int surfaceFlingerCount;
- ProcessDmabuf(int retainedSizeKb, int retainedBuffersCount,
- int mappedSizeKb, int mappedBuffersCount) {
+ ProcessDmabuf(int uid, String processName, int oomScore, int retainedSizeKb,
+ int retainedBuffersCount, int surfaceFlingerSizeKb,
+ int surfaceFlingerCount) {
+ this.uid = uid;
+ this.processName = processName;
+ this.oomScore = oomScore;
this.retainedSizeKb = retainedSizeKb;
this.retainedBuffersCount = retainedBuffersCount;
- this.mappedSizeKb = mappedSizeKb;
- this.mappedBuffersCount = mappedBuffersCount;
+ this.surfaceFlingerSizeKb = surfaceFlingerSizeKb;
+ this.surfaceFlingerCount = surfaceFlingerCount;
}
}
@@ -47,7 +55,7 @@
* stats could not be read.
*/
@Nullable
- public static native ProcessDmabuf getDmabufAllocations(int pid);
+ public static native ProcessDmabuf[] getDmabufAllocations();
/** Pid to gpu memory size. */
public static final class ProcessGpuMem {
diff --git a/core/java/com/android/internal/widget/CachingIconView.java b/core/java/com/android/internal/widget/CachingIconView.java
index bd27e60..299cbe1 100644
--- a/core/java/com/android/internal/widget/CachingIconView.java
+++ b/core/java/com/android/internal/widget/CachingIconView.java
@@ -23,7 +23,6 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Configuration;
-import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
@@ -36,9 +35,6 @@
import android.widget.ImageView;
import android.widget.RemoteViews;
-import com.android.internal.R;
-
-import java.io.IOException;
import java.util.Objects;
import java.util.function.Consumer;
@@ -59,42 +55,9 @@
private int mBackgroundColor;
private boolean mWillBeForceHidden;
- private int mMaxDrawableWidth = -1;
- private int mMaxDrawableHeight = -1;
-
- public CachingIconView(Context context) {
- this(context, null, 0, 0);
- }
-
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public CachingIconView(Context context, @Nullable AttributeSet attrs) {
- this(context, attrs, 0, 0);
- }
-
- public CachingIconView(Context context, @Nullable AttributeSet attrs,
- int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public CachingIconView(Context context, @Nullable AttributeSet attrs,
- int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- init(context, attrs, defStyleAttr, defStyleRes);
- }
-
- private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- if (attrs == null) {
- return;
- }
-
- TypedArray ta = context.obtainStyledAttributes(attrs,
- R.styleable.CachingIconView, defStyleAttr, defStyleRes);
- mMaxDrawableWidth = ta.getDimensionPixelSize(R.styleable
- .CachingIconView_maxDrawableWidth, -1);
- mMaxDrawableHeight = ta.getDimensionPixelSize(R.styleable
- .CachingIconView_maxDrawableHeight, -1);
- ta.recycle();
+ super(context, attrs);
}
@Override
@@ -103,31 +66,15 @@
if (!testAndSetCache(icon)) {
mInternalSetDrawable = true;
// This calls back to setImageDrawable, make sure we don't clear the cache there.
- Drawable drawable = loadSizeRestrictedIcon(icon);
- if (drawable == null) {
- super.setImageIcon(icon);
- } else {
- super.setImageDrawable(drawable);
- }
+ super.setImageIcon(icon);
mInternalSetDrawable = false;
}
}
- @Nullable
- private Drawable loadSizeRestrictedIcon(@Nullable Icon icon) {
- try {
- return LocalImageResolver.resolveImage(icon, getContext(), mMaxDrawableWidth,
- mMaxDrawableHeight);
- } catch (IOException e) {
- return null;
- }
- }
-
@Override
- public Runnable setImageIconAsync(@Nullable final Icon icon) {
+ public Runnable setImageIconAsync(@Nullable Icon icon) {
resetCache();
- Drawable drawable = loadSizeRestrictedIcon(icon);
- return () -> setImageDrawable(drawable);
+ return super.setImageIconAsync(icon);
}
@Override
@@ -136,34 +83,14 @@
if (!testAndSetCache(resId)) {
mInternalSetDrawable = true;
// This calls back to setImageDrawable, make sure we don't clear the cache there.
- Drawable drawable = loadSizeRestrictedDrawable(resId);
- if (drawable == null) {
- super.setImageResource(resId);
- } else {
- super.setImageDrawable(drawable);
- }
+ super.setImageResource(resId);
mInternalSetDrawable = false;
}
}
- @Nullable
- private Drawable loadSizeRestrictedDrawable(@DrawableRes int resId) {
- try {
- return LocalImageResolver.resolveImage(resId, getContext(), mMaxDrawableWidth,
- mMaxDrawableHeight);
- } catch (IOException e) {
- return null;
- }
- }
-
@Override
public Runnable setImageResourceAsync(@DrawableRes int resId) {
resetCache();
- Drawable drawable = loadSizeRestrictedDrawable(resId);
- if (drawable != null) {
- return () -> setImageDrawable(drawable);
- }
-
return super.setImageResourceAsync(resId);
}
@@ -171,35 +98,13 @@
@RemotableViewMethod(asyncImpl="setImageURIAsync")
public void setImageURI(@Nullable Uri uri) {
resetCache();
- Drawable drawable = loadSizeRestrictedUri(uri);
- if (drawable == null) {
- super.setImageURI(uri);
- } else {
- mInternalSetDrawable = true;
- super.setImageDrawable(drawable);
- mInternalSetDrawable = false;
- }
- }
-
- @Nullable
- private Drawable loadSizeRestrictedUri(@Nullable Uri uri) {
- try {
- return LocalImageResolver.resolveImage(uri, getContext(), mMaxDrawableWidth,
- mMaxDrawableHeight);
- } catch (IOException e) {
- return null;
- }
+ super.setImageURI(uri);
}
@Override
public Runnable setImageURIAsync(@Nullable Uri uri) {
resetCache();
- Drawable drawable = loadSizeRestrictedUri(uri);
- if (drawable == null) {
- return super.setImageURIAsync(uri);
- } else {
- return () -> setImageDrawable(drawable);
- }
+ return super.setImageURIAsync(uri);
}
@Override
@@ -402,18 +307,4 @@
public void setWillBeForceHidden(boolean forceHidden) {
mWillBeForceHidden = forceHidden;
}
-
- /**
- * Returns the set maximum width of drawable in pixels. -1 if not set.
- */
- public int getMaxDrawableWidth() {
- return mMaxDrawableWidth;
- }
-
- /**
- * Returns the set maximum height of drawable in pixels. -1 if not set.
- */
- public int getMaxDrawableHeight() {
- return mMaxDrawableHeight;
- }
}
diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java
index 66a3ff9..616b699 100644
--- a/core/java/com/android/internal/widget/LocalImageResolver.java
+++ b/core/java/com/android/internal/widget/LocalImageResolver.java
@@ -16,25 +16,21 @@
package com.android.internal.widget;
-import android.annotation.DrawableRes;
import android.annotation.Nullable;
import android.content.Context;
-import android.graphics.Bitmap;
import android.graphics.ImageDecoder;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.util.Size;
-import com.android.internal.annotations.VisibleForTesting;
-
import java.io.IOException;
/** A class to extract Drawables from a MessagingStyle/ConversationStyle message. */
public class LocalImageResolver {
+ private static final String TAG = LocalImageResolver.class.getSimpleName();
- @VisibleForTesting
- static final int DEFAULT_MAX_SAFE_ICON_SIZE_PX = 480;
+ private static final int MAX_SAFE_ICON_SIZE_PX = 480;
/**
* Resolve an image from the given Uri using {@link ImageDecoder}
@@ -42,9 +38,9 @@
public static Drawable resolveImage(Uri uri, Context context) throws IOException {
final ImageDecoder.Source source =
ImageDecoder.createSource(context.getContentResolver(), uri);
- return ImageDecoder.decodeDrawable(source,
- (decoder, info, s) -> LocalImageResolver.onHeaderDecoded(decoder, info,
- DEFAULT_MAX_SAFE_ICON_SIZE_PX, DEFAULT_MAX_SAFE_ICON_SIZE_PX));
+ final Drawable drawable =
+ ImageDecoder.decodeDrawable(source, LocalImageResolver::onHeaderDecoded);
+ return drawable;
}
/**
@@ -52,49 +48,17 @@
* using {@link Icon#loadDrawable(Context)} otherwise. This will correctly apply the Icon's,
* tint, if present, to the drawable.
*/
- public static Drawable resolveImage(@Nullable Icon icon, Context context)
- throws IOException {
- return resolveImage(icon, context, DEFAULT_MAX_SAFE_ICON_SIZE_PX,
- DEFAULT_MAX_SAFE_ICON_SIZE_PX);
- }
-
- /**
- * Get the drawable from Icon using {@link ImageDecoder} if it contains a Uri, or
- * using {@link Icon#loadDrawable(Context)} otherwise. This will correctly apply the Icon's,
- * tint, if present, to the drawable.
- */
- @Nullable
- public static Drawable resolveImage(@Nullable Icon icon, Context context, int maxWidth,
- int maxHeight)
- throws IOException {
- if (icon == null) {
- return null;
+ public static Drawable resolveImage(Icon icon, Context context) throws IOException {
+ Uri uri = getResolvableUri(icon);
+ if (uri != null) {
+ Drawable result = resolveImage(uri, context);
+ if (icon.hasTint()) {
+ result.mutate();
+ result.setTintList(icon.getTintList());
+ result.setTintBlendMode(icon.getTintBlendMode());
+ }
+ return result;
}
-
- switch (icon.getType()) {
- case Icon.TYPE_URI:
- case Icon.TYPE_URI_ADAPTIVE_BITMAP:
- Uri uri = getResolvableUri(icon);
- if (uri != null) {
- Drawable result = resolveImage(uri, context, maxWidth, maxHeight);
- return tintDrawable(icon, result);
- }
- break;
- case Icon.TYPE_RESOURCE:
- Drawable result = resolveImage(icon.getResId(), context, maxWidth, maxHeight);
- if (result != null) {
- return tintDrawable(icon, result);
- }
- break;
- case Icon.TYPE_BITMAP:
- case Icon.TYPE_ADAPTIVE_BITMAP:
- return resolveBitmapImage(icon, context, maxWidth, maxHeight);
- case Icon.TYPE_DATA: // We can't really improve on raw data images.
- default:
- break;
- }
-
- // Fallback to straight drawable load if we fail with more efficient approach.
return icon.loadDrawable(context);
}
@@ -102,71 +66,7 @@
throws IOException {
final ImageDecoder.Source source =
ImageDecoder.createSource(context.getContentResolver(), uri);
- return resolveImage(source, maxWidth, maxHeight);
- }
-
- /**
- * Attempts to resolve the resource as a bitmap drawable constrained within max sizes.
- *
- * @return decoded drawable or null if the passed resource is not a straight bitmap
- */
- @Nullable
- public static Drawable resolveImage(@DrawableRes int resId, Context context, int maxWidth,
- int maxHeight)
- throws IOException {
- final ImageDecoder.Source source = ImageDecoder.createSource(context.getResources(), resId);
- // It's possible that the resource isn't an actual bitmap drawable so this decode can fail.
- // Return null in that case.
- try {
- return resolveImage(source, maxWidth, maxHeight);
- } catch (ImageDecoder.DecodeException e) {
- return null;
- }
- }
-
- @Nullable
- private static Drawable resolveBitmapImage(Icon icon, Context context, int maxWidth,
- int maxHeight) {
- Bitmap bitmap = icon.getBitmap();
- if (bitmap == null) {
- return null;
- }
-
- if (bitmap.getWidth() > maxWidth || bitmap.getHeight() > maxHeight) {
- Icon smallerIcon = icon.getType() == Icon.TYPE_ADAPTIVE_BITMAP
- ? Icon.createWithAdaptiveBitmap(bitmap) : Icon.createWithBitmap(bitmap);
- // We don't want to modify the source icon, create a copy.
- smallerIcon.setTintList(icon.getTintList())
- .setTintBlendMode(icon.getTintBlendMode())
- .scaleDownIfNecessary(maxWidth, maxHeight);
- return smallerIcon.loadDrawable(context);
- }
-
- return icon.loadDrawable(context);
- }
-
- @Nullable
- private static Drawable tintDrawable(Icon icon, @Nullable Drawable drawable) {
- if (drawable == null) {
- return null;
- }
-
- if (icon.hasTint()) {
- drawable.mutate();
- drawable.setTintList(icon.getTintList());
- drawable.setTintBlendMode(icon.getTintBlendMode());
- }
-
- return drawable;
- }
-
- private static Drawable resolveImage(ImageDecoder.Source source, int maxWidth, int maxHeight)
- throws IOException {
return ImageDecoder.decodeDrawable(source, (decoder, info, unused) -> {
- if (maxWidth <= 0 || maxHeight <= 0) {
- return;
- }
-
final Size size = info.getSize();
if (size.getWidth() > size.getHeight()) {
if (size.getWidth() > maxWidth) {
@@ -188,12 +88,11 @@
}
private static void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info,
- int maxWidth, int maxHeight) {
+ ImageDecoder.Source source) {
final Size size = info.getSize();
final int originalSize = Math.max(size.getHeight(), size.getWidth());
- final int maxSize = Math.max(maxWidth, maxHeight);
- final double ratio = (originalSize > maxSize)
- ? originalSize * 1f / maxSize
+ final double ratio = (originalSize > MAX_SAFE_ICON_SIZE_PX)
+ ? originalSize * 1f / MAX_SAFE_ICON_SIZE_PX
: 1.0;
decoder.setTargetSampleSize(getPowerOfTwoForSampleRatio(ratio));
}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index cc7e9d9..e281853 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -34,6 +34,7 @@
import android.os.incremental.IncrementalManager;
import android.os.storage.StorageManager;
import android.permission.PermissionManager.SplitPermissionInfo;
+import android.sysprop.ApexProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -1187,7 +1188,8 @@
boolean systemExt = permFile.toPath().startsWith(
Environment.getSystemExtDirectory().toPath() + "/");
boolean apex = permFile.toPath().startsWith(
- Environment.getApexDirectory().toPath() + "/");
+ Environment.getApexDirectory().toPath() + "/")
+ && ApexProperties.updatable().orElse(false);
if (vendor) {
readPrivAppPermissions(parser, mVendorPrivAppPermissions,
mVendorPrivAppDenyPermissions);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 3a76745..a1be884 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -272,6 +272,7 @@
"libinput",
"libcamera_client",
"libcamera_metadata",
+ "libprocinfo",
"libsqlite",
"libEGL",
"libGLESv1_CM",
diff --git a/core/jni/com_android_internal_os_KernelAllocationStats.cpp b/core/jni/com_android_internal_os_KernelAllocationStats.cpp
index e0a24430..5b10497 100644
--- a/core/jni/com_android_internal_os_KernelAllocationStats.cpp
+++ b/core/jni/com_android_internal_os_KernelAllocationStats.cpp
@@ -13,12 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <dmabufinfo/dmabufinfo.h>
#include <jni.h>
#include <meminfo/sysmeminfo.h>
+#include <procinfo/process.h>
#include "core_jni_helpers.h"
+using DmaBuffer = ::android::dmabufinfo::DmaBuffer;
+using android::base::ReadFileToString;
+using android::base::StringPrintf;
+
namespace {
static jclass gProcessDmabufClazz;
static jmethodID gProcessDmabufCtor;
@@ -28,30 +35,127 @@
namespace android {
-static jobject KernelAllocationStats_getDmabufAllocations(JNIEnv *env, jobject, jint pid) {
- std::vector<dmabufinfo::DmaBuffer> buffers;
- if (!dmabufinfo::ReadDmaBufMapRefs(pid, &buffers)) {
+struct PidDmaInfo {
+ uid_t uid;
+ std::string cmdline;
+ int oomScoreAdj;
+};
+
+static jobjectArray KernelAllocationStats_getDmabufAllocations(JNIEnv *env, jobject) {
+ std::vector<DmaBuffer> buffers;
+
+ if (!dmabufinfo::ReadDmaBufs(&buffers)) {
return nullptr;
}
- jint mappedSize = 0;
- jint mappedCount = buffers.size();
- for (const auto &buffer : buffers) {
- mappedSize += buffer.size();
- }
- mappedSize /= 1024;
- jint retainedSize = -1;
- jint retainedCount = -1;
- if (dmabufinfo::ReadDmaBufFdRefs(pid, &buffers)) {
- retainedCount = buffers.size();
- retainedSize = 0;
- for (const auto &buffer : buffers) {
- retainedSize += buffer.size();
+ // Create a reverse map from pid to dmabufs
+ // Store dmabuf inodes & sizes for later processing.
+ std::unordered_map<pid_t, std::set<ino_t>> pidToInodes;
+ std::unordered_map<ino_t, long> inodeToSize;
+ for (auto &buf : buffers) {
+ for (auto pid : buf.pids()) {
+ pidToInodes[pid].insert(buf.inode());
}
- retainedSize /= 1024;
+ inodeToSize[buf.inode()] = buf.size();
}
- return env->NewObject(gProcessDmabufClazz, gProcessDmabufCtor, retainedSize, retainedCount,
- mappedSize, mappedCount);
+
+ pid_t surfaceFlingerPid = -1;
+ // The set of all inodes that are being retained by SurfaceFlinger. Buffers
+ // shared between another process and SF will appear in this set.
+ std::set<ino_t> surfaceFlingerBufferInodes;
+ // The set of all inodes that are being retained by any process other
+ // than SurfaceFlinger. Buffers shared between another process and SF will
+ // appear in this set.
+ std::set<ino_t> otherProcessBufferInodes;
+
+ // Find SurfaceFlinger pid & get cmdlines, oomScoreAdj, etc for each pid
+ // holding any DMA buffers.
+ std::unordered_map<pid_t, PidDmaInfo> pidDmaInfos;
+ for (const auto &pidToInodeEntry : pidToInodes) {
+ pid_t pid = pidToInodeEntry.first;
+
+ android::procinfo::ProcessInfo processInfo;
+ if (!android::procinfo::GetProcessInfo(pid, &processInfo)) {
+ continue;
+ }
+
+ std::string cmdline;
+ if (!ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &cmdline)) {
+ continue;
+ }
+
+ // cmdline strings are null-delimited, so we split on \0 here
+ if (cmdline.substr(0, cmdline.find('\0')) == "/system/bin/surfaceflinger") {
+ if (surfaceFlingerPid == -1) {
+ surfaceFlingerPid = pid;
+ surfaceFlingerBufferInodes = pidToInodes[pid];
+ } else {
+ LOG(ERROR) << "getDmabufAllocations found multiple SF processes; pid1: " << pid
+ << ", pid2:" << surfaceFlingerPid;
+ surfaceFlingerPid = -2; // Used as a sentinel value below
+ }
+ } else {
+ otherProcessBufferInodes.insert(pidToInodes[pid].begin(), pidToInodes[pid].end());
+ }
+
+ std::string oomScoreAdjStr;
+ if (!ReadFileToString(StringPrintf("/proc/%d/oom_score_adj", pid), &oomScoreAdjStr)) {
+ continue;
+ }
+
+ pidDmaInfos[pid] = PidDmaInfo{.uid = processInfo.uid,
+ .cmdline = cmdline,
+ .oomScoreAdj = atoi(oomScoreAdjStr.c_str())};
+ }
+
+ if (surfaceFlingerPid < 0) {
+ LOG(ERROR) << "getDmabufAllocations could not identify SurfaceFlinger "
+ << "process via /proc/pid/cmdline";
+ }
+
+ jobjectArray ret = env->NewObjectArray(pidDmaInfos.size(), gProcessDmabufClazz, NULL);
+ int retArrayIndex = 0;
+ for (const auto &pidDmaInfosEntry : pidDmaInfos) {
+ pid_t pid = pidDmaInfosEntry.first;
+
+ // For all processes apart from SurfaceFlinger, this set will store the
+ // dmabuf inodes that are shared with SF. For SF, it will store the inodes
+ // that are shared with any other process.
+ std::set<ino_t> sharedBuffers;
+ if (pid == surfaceFlingerPid) {
+ set_intersection(surfaceFlingerBufferInodes.begin(), surfaceFlingerBufferInodes.end(),
+ otherProcessBufferInodes.begin(), otherProcessBufferInodes.end(),
+ std::inserter(sharedBuffers, sharedBuffers.end()));
+ } else if (surfaceFlingerPid > 0) {
+ set_intersection(pidToInodes[pid].begin(), pidToInodes[pid].end(),
+ surfaceFlingerBufferInodes.begin(), surfaceFlingerBufferInodes.end(),
+ std::inserter(sharedBuffers, sharedBuffers.begin()));
+ } // If surfaceFlingerPid < 0; it means we failed to identify it, and
+ // the SF-related fields below should be left empty.
+
+ long totalSize = 0;
+ long sharedBuffersSize = 0;
+ for (const auto &inode : pidToInodes[pid]) {
+ totalSize += inodeToSize[inode];
+ if (sharedBuffers.count(inode)) {
+ sharedBuffersSize += inodeToSize[inode];
+ }
+ }
+
+ jobject obj = env->NewObject(gProcessDmabufClazz, gProcessDmabufCtor,
+ /* uid */ pidDmaInfos[pid].uid,
+ /* process name */
+ env->NewStringUTF(pidDmaInfos[pid].cmdline.c_str()),
+ /* oomscore */ pidDmaInfos[pid].oomScoreAdj,
+ /* retainedSize */ totalSize / 1024,
+ /* retainedCount */ pidToInodes[pid].size(),
+ /* sharedWithSurfaceFlinger size */ sharedBuffersSize / 1024,
+ /* sharedWithSurfaceFlinger count */ sharedBuffers.size());
+
+ env->SetObjectArrayElement(ret, retArrayIndex++, obj);
+ }
+
+ return ret;
}
static jobject KernelAllocationStats_getGpuAllocations(JNIEnv *env) {
@@ -74,7 +178,7 @@
}
static const JNINativeMethod methods[] = {
- {"getDmabufAllocations", "(I)Lcom/android/internal/os/KernelAllocationStats$ProcessDmabuf;",
+ {"getDmabufAllocations", "()[Lcom/android/internal/os/KernelAllocationStats$ProcessDmabuf;",
(void *)KernelAllocationStats_getDmabufAllocations},
{"getGpuAllocations", "()[Lcom/android/internal/os/KernelAllocationStats$ProcessGpuMem;",
(void *)KernelAllocationStats_getGpuAllocations},
@@ -86,7 +190,8 @@
jclass clazz =
FindClassOrDie(env, "com/android/internal/os/KernelAllocationStats$ProcessDmabuf");
gProcessDmabufClazz = MakeGlobalRefOrDie(env, clazz);
- gProcessDmabufCtor = GetMethodIDOrDie(env, gProcessDmabufClazz, "<init>", "(IIII)V");
+ gProcessDmabufCtor =
+ GetMethodIDOrDie(env, gProcessDmabufClazz, "<init>", "(ILjava/lang/String;IIIII)V");
clazz = FindClassOrDie(env, "com/android/internal/os/KernelAllocationStats$ProcessGpuMem");
gProcessGpuMemClazz = MakeGlobalRefOrDie(env, clazz);
@@ -94,4 +199,4 @@
return res;
}
-} // namespace android
+} // namespace android
\ No newline at end of file
diff --git a/core/proto/android/os/appbatterystats.proto b/core/proto/android/os/appbatterystats.proto
new file mode 100644
index 0000000..8769ebb
--- /dev/null
+++ b/core/proto/android/os/appbatterystats.proto
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package android.os;
+
+option java_multiple_files = true;
+
+message AppBatteryStatsProto {
+ message UidStats {
+ optional int32 uid = 1;
+
+ message ProcessStateStats {
+ enum ProcessState {
+ UNSPECIFIED = 0;
+ FOREGROUND = 1;
+ BACKGROUND = 2;
+ FOREGROUND_SERVICE = 3;
+ CACHED = 4;
+ }
+
+ optional ProcessState process_state = 1;
+
+ // Time spent in this state in the past 24 hours
+ optional int64 duration_ms = 2;
+ // Estimated power consumed in this state in the past 24 hours
+ optional double power_mah = 3;
+ }
+
+ repeated ProcessStateStats process_state_stats = 2;
+ }
+
+ repeated UidStats uid_stats = 1;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 729bc82..d652b2f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6051,10 +6051,10 @@
<permission android:name="android.permission.MANAGE_APPOPS"
android:protectionLevel="signature" />
- <!-- @SystemApi Permission that allows background clipboard access.
- @hide Not for use by third-party applications. -->
+ <!-- @hide Permission that allows background clipboard access.
+ <p>Not for use by third-party applications. -->
<permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND"
- android:protectionLevel="internal|role" />
+ android:protectionLevel="signature" />
<!-- @hide Permission that suppresses the notification when the clipboard is accessed.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SUPPRESS_CLIPBOARD_ACCESS_NOTIFICATION"
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index a7f2aa7..81a79c5 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -49,8 +49,6 @@
android:layout_marginStart="@dimen/notification_icon_circle_start"
android:background="@drawable/notification_icon_circle"
android:padding="@dimen/notification_icon_circle_padding"
- android:maxDrawableWidth="@dimen/notification_icon_circle_size"
- android:maxDrawableHeight="@dimen/notification_icon_circle_size"
/>
<!-- extends ViewGroup -->
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index fd787f6..c6983ae 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -45,8 +45,6 @@
android:layout_marginStart="@dimen/notification_icon_circle_start"
android:background="@drawable/notification_icon_circle"
android:padding="@dimen/notification_icon_circle_padding"
- android:maxDrawableWidth="@dimen/notification_icon_circle_size"
- android:maxDrawableHeight="@dimen/notification_icon_circle_size"
/>
<FrameLayout
@@ -138,7 +136,7 @@
</LinearLayout>
- <com.android.internal.widget.CachingIconView
+ <ImageView
android:id="@+id/right_icon"
android:layout_width="@dimen/notification_right_icon_size"
android:layout_height="@dimen/notification_right_icon_size"
@@ -150,8 +148,6 @@
android:clipToOutline="true"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
- android:maxDrawableWidth="@dimen/notification_right_icon_size"
- android:maxDrawableHeight="@dimen/notification_right_icon_size"
/>
<FrameLayout
diff --git a/core/res/res/layout/notification_template_right_icon.xml b/core/res/res/layout/notification_template_right_icon.xml
index 8b3b795..f163ed5 100644
--- a/core/res/res/layout/notification_template_right_icon.xml
+++ b/core/res/res/layout/notification_template_right_icon.xml
@@ -13,7 +13,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<com.android.internal.widget.CachingIconView
+<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/right_icon"
android:layout_width="@dimen/notification_right_icon_size"
@@ -25,6 +25,4 @@
android:clipToOutline="true"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
- android:maxDrawableWidth="@dimen/notification_right_icon_size"
- android:maxDrawableHeight="@dimen/notification_right_icon_size"
/>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b3203ae..2107f65 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -9807,12 +9807,4 @@
of the supported locale. {@link android.app.LocaleConfig} -->
<attr name="name" />
</declare-styleable>
-
- <!-- @hide -->
- <declare-styleable name="CachingIconView">
- <!-- Maximum width of displayed drawable. Drawables exceeding this size will be downsampled. -->
- <attr name="maxDrawableWidth" format="dimension"/>
- <!-- Maximum width of height drawable. Drawables exceeding this size will be downsampled. -->
- <attr name="maxDrawableHeight" format="dimension"/>
- </declare-styleable>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 269aa1b..62b3054 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4857,6 +4857,7 @@
<item>0.25</item>
<item>0.5</item>
<item>0.75</item>
+ <item>0.875</item>
</string-array>
<!-- Messages that should not be shown to the user during face auth enrollment. This should be
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 0a4c4c0..2dc17b8 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -148,10 +148,6 @@
<public name="supportsInlineSuggestionsWithTouchExploration" />
<public name="lineBreakStyle" />
<public name="lineBreakWordStyle" />
- <!-- @hide -->
- <public name="maxDrawableWidth" />
- <!-- @hide -->
- <public name="maxDrawableHeight" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01de0000">
diff --git a/core/tests/coretests/res/drawable/big_a.png b/core/tests/coretests/res/drawable/big_a.png
deleted file mode 100644
index dc059a3..0000000
--- a/core/tests/coretests/res/drawable/big_a.png
+++ /dev/null
Binary files differ
diff --git a/core/tests/coretests/res/layout/caching_icon_view_test_max_size.xml b/core/tests/coretests/res/layout/caching_icon_view_test_max_size.xml
deleted file mode 100644
index 9a03446..0000000
--- a/core/tests/coretests/res/layout/caching_icon_view_test_max_size.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<com.android.internal.widget.CachingIconView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/caching_icon_view"
- android:layout_width="120dp"
- android:layout_height="120dp"
- android:maxDrawableWidth="80dp"
- android:maxDrawableHeight="80dp" />
diff --git a/core/tests/coretests/res/layout/caching_icon_view_test_no_max_size.xml b/core/tests/coretests/res/layout/caching_icon_view_test_no_max_size.xml
deleted file mode 100644
index a213a97..0000000
--- a/core/tests/coretests/res/layout/caching_icon_view_test_no_max_size.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<com.android.internal.widget.CachingIconView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/caching_icon_view"
- android:layout_width="120dp"
- android:layout_height="120dp" />
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
index 1ae9649..e303934 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
@@ -60,7 +60,7 @@
@RunWith(AndroidJUnit4.class)
public class HandwritingInitiatorTest {
private static final int TOUCH_SLOP = 8;
- private static final long TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
+ private static final long TIMEOUT = ViewConfiguration.getLongPressTimeout();
private static final Rect sHwArea = new Rect(100, 200, 500, 500);
private HandwritingInitiator mHandwritingInitiator;
@@ -177,7 +177,7 @@
}
@Test
- public void onTouchEvent_notStartHandwriting_when_stylusMove_afterTapTimeOut() {
+ public void onTouchEvent_notStartHandwriting_when_stylusMove_afterTimeOut() {
mHandwritingInitiator.onInputConnectionCreated(mTestView);
final int x1 = 10;
final int y1 = 10;
@@ -187,7 +187,7 @@
final int x2 = x1 + TOUCH_SLOP * 2;
final int y2 = y1;
- final long time2 = time1 + TAP_TIMEOUT + 10L;
+ final long time2 = time1 + TIMEOUT + 10L;
MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, time2);
mHandwritingInitiator.onTouchEvent(stylusEvent2);
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index ec45a01..625f52a 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -232,7 +232,7 @@
assertThat(entry3.handlerClassName).isEqualTo(
"com.android.internal.os.LooperStatsTest$TestHandlerSecond");
assertThat(entry3.messageName).startsWith(
- "com.android.internal.os.LooperStatsTest$$ExternalSyntheticLambda5");
+ "com.android.internal.os.LooperStatsTest$$ExternalSyntheticLambda");
assertThat(entry3.messageCount).isEqualTo(1);
assertThat(entry3.recordedMessageCount).isEqualTo(1);
assertThat(entry3.exceptionCount).isEqualTo(0);
diff --git a/core/tests/coretests/src/com/android/internal/widget/CachingIconViewTest.java b/core/tests/coretests/src/com/android/internal/widget/CachingIconViewTest.java
deleted file mode 100644
index 0d4b449..0000000
--- a/core/tests/coretests/src/com/android/internal/widget/CachingIconViewTest.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.graphics.drawable.InsetDrawable;
-import android.net.Uri;
-import android.util.TypedValue;
-import android.view.LayoutInflater;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import com.android.frameworks.coretests.R;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class CachingIconViewTest {
-
- private Context mContext;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
- }
-
- @Test
- public void customDrawable_setImageIcon_skipsResizeSuccessfully() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_max_size, null);
- view.setImageIcon(Icon.createWithResource(mContext, R.drawable.custom_drawable));
- Drawable drawable = view.getDrawable();
- assertThat(drawable).isInstanceOf(InsetDrawable.class);
- }
-
- @Test
- public void customDrawable_setImageIconAsync_skipsResizeSuccessfully() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_max_size, null);
- view.setImageIconAsync(Icon.createWithResource(mContext, R.drawable.custom_drawable)).run();
- Drawable drawable = view.getDrawable();
- assertThat(drawable).isInstanceOf(InsetDrawable.class);
- }
-
- @Test
- public void customDrawable_setImageResource_skipsResizeSuccessfully() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_max_size, null);
- view.setImageResource(R.drawable.custom_drawable);
- Drawable drawable = view.getDrawable();
- assertThat(drawable).isInstanceOf(InsetDrawable.class);
- }
-
- @Test
- public void customDrawable_setImageResourceAsync_skipsResizeSuccessfully() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_max_size, null);
- view.setImageResourceAsync(R.drawable.custom_drawable).run();
- Drawable drawable = view.getDrawable();
- assertThat(drawable).isInstanceOf(InsetDrawable.class);
- }
-
- @Test
- public void customDrawable_setImageUri_skipsResizeSuccessfully() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_max_size, null);
- view.setImageURI(Uri.parse(
- "android.resource://com.android.frameworks.coretests/"
- + R.drawable.custom_drawable));
- Drawable drawable = view.getDrawable();
- assertThat(drawable).isInstanceOf(InsetDrawable.class);
- }
-
- @Test
- public void customDrawable_setImageUriAsync_skipsResizeSuccessfully() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_max_size, null);
- view.setImageURIAsync(Uri.parse(
- "android.resource://com.android.frameworks.coretests/"
- + R.drawable.custom_drawable)).run();
- Drawable drawable = view.getDrawable();
- assertThat(drawable).isInstanceOf(InsetDrawable.class);
- }
-
- @Test
- public void maxDrawableDimensionsSet_setImageIcon_resizesImageIcon() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_max_size, null);
- view.setImageIcon(Icon.createWithResource(mContext, R.drawable.big_a));
-
- assertDrawableResized(view);
- }
-
- @Test
- public void maxDrawableWithNoDimensionsSet_setImageIcon_doesNotResizeImageIcon() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_no_max_size, null);
- view.setImageIcon(Icon.createWithResource(mContext, R.drawable.big_a));
-
- assertDrawableNotResized(view);
- }
-
- @Test
- public void maxDrawableDimensionsSet_setImageIconAsync_resizesImageIcon() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_max_size, null);
- view.setImageIconAsync(Icon.createWithResource(mContext, R.drawable.big_a)).run();
-
- assertDrawableResized(view);
- }
-
- @Test
- public void maxDrawableWithNoDimensionsSet_setImageIconAsync_doesNotResizeImageIcon() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_no_max_size, null);
- view.setImageIconAsync(Icon.createWithResource(mContext, R.drawable.big_a)).run();
-
- assertDrawableNotResized(view);
- }
-
- @Test
- public void maxDrawableDimensionsSet_setImageResource_resizesImageIcon() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_max_size, null);
- view.setImageResource(R.drawable.big_a);
-
- assertDrawableResized(view);
- }
-
- @Test
- public void maxDrawableWithNoDimensionsSet_setImageResource_doesNotResizeImageIcon() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_no_max_size, null);
- view.setImageResource(R.drawable.big_a);
-
- assertDrawableNotResized(view);
- }
-
- @Test
- public void maxDrawableDimensionsSet_setImageResourceAsync_resizesImageIcon() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_max_size, null);
- view.setImageResourceAsync(R.drawable.big_a).run();
-
- assertDrawableResized(view);
- }
-
- @Test
- public void maxDrawableWithNoDimensionsSet_setImageResourceAsync_doesNotResizeImageIcon() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_no_max_size, null);
- view.setImageResourceAsync(R.drawable.big_a).run();
-
- assertDrawableNotResized(view);
- }
-
- @Test
- public void maxDrawableDimensionsSet_setImageUri_resizesImageIcon() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_max_size, null);
- view.setImageURI(Uri.parse(
- "android.resource://com.android.frameworks.coretests/" + R.drawable.big_a));
-
- assertDrawableResized(view);
- }
-
- @Test
- public void maxDrawableWithNoDimensionsSet_setImageUri_doesNotResizeImageIcon() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_no_max_size, null);
- view.setImageURI(Uri.parse(
- "android.resource://com.android.frameworks.coretests/" + R.drawable.big_a));
-
- assertDrawableNotResized(view);
- }
-
- @Test
- public void maxDrawableDimensionsSet_setImageUriAsync_resizesImageIcon() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_max_size, null);
- view.setImageURIAsync(Uri.parse(
- "android.resource://com.android.frameworks.coretests/" + R.drawable.big_a)).run();
-
- assertDrawableResized(view);
- }
-
- @Test
- public void maxDrawableWithNoDimensionsSet_setImageUriAsync_doesNotResizeImageIcon() {
- CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
- R.layout.caching_icon_view_test_no_max_size, null);
- view.setImageURIAsync(Uri.parse(
- "android.resource://com.android.frameworks.coretests/" + R.drawable.big_a)).run();
-
- assertDrawableNotResized(view);
- }
-
-
- private void assertDrawableResized(@Nullable CachingIconView view) {
- assertThat(view).isNotNull();
- int maxSize =
- (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 80f,
- mContext.getResources().getDisplayMetrics());
- assertThat(view.getMaxDrawableHeight()).isEqualTo(maxSize);
- assertThat(view.getMaxDrawableWidth()).isEqualTo(maxSize);
-
- Drawable drawable = view.getDrawable();
- assertThat(drawable).isInstanceOf(BitmapDrawable.class);
- BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
- assertThat(bitmapDrawable.getBitmap().getWidth()).isLessThan(maxSize + 1);
- assertThat(bitmapDrawable.getBitmap().getHeight()).isLessThan(maxSize + 1);
- }
-
- private void assertDrawableNotResized(@Nullable CachingIconView view) {
- assertThat(view).isNotNull();
- int maxSize =
- (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 80f,
- mContext.getResources().getDisplayMetrics());
- assertThat(view.getMaxDrawableHeight()).isEqualTo(-1);
- assertThat(view.getMaxDrawableWidth()).isEqualTo(-1);
-
- Drawable drawable = view.getDrawable();
- assertThat(drawable).isInstanceOf(BitmapDrawable.class);
- BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
- assertThat(bitmapDrawable.getBitmap().getWidth()).isGreaterThan(maxSize);
- assertThat(bitmapDrawable.getBitmap().getHeight()).isGreaterThan(maxSize);
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java b/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
deleted file mode 100644
index 8dcb4a2..0000000
--- a/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.content.Context;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-
-import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import com.android.frameworks.coretests.R;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.IOException;
-
-@RunWith(AndroidJUnit4ClassRunner.class)
-public class LocalImageResolverTest {
-
- private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
-
- @Test
- public void resolveImage_largeBitmapIcon_defaultSize_resizeToDefaultSize() throws
- IOException {
- Icon icon = Icon.createWithBitmap(
- BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
- Drawable d = LocalImageResolver.resolveImage(icon, mContext);
-
- assertThat(d).isInstanceOf(BitmapDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) d;
- // No isLessOrEqualThan sadly.
- assertThat(bd.getBitmap().getWidth()).isLessThan(
- LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
- assertThat(bd.getBitmap().getHeight()).isLessThan(
- LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
- }
-
- @Test
- public void resolveImage_largeAdaptiveBitmapIcon_defaultSize_resizeToDefaultSize() throws
- IOException {
- Icon icon = Icon.createWithAdaptiveBitmap(
- BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
- Drawable d = LocalImageResolver.resolveImage(icon, mContext);
-
- assertThat(d).isInstanceOf(AdaptiveIconDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) ((AdaptiveIconDrawable) d).getForeground();
- // No isLessOrEqualThan sadly.
- assertThat(bd.getBitmap().getWidth()).isLessThan(
- LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
- assertThat(bd.getBitmap().getHeight()).isLessThan(
- LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
- }
-
- @Test
- public void resolveImage_largeResourceIcon_defaultSize_resizeToDefaultSize() throws
- IOException {
- Icon icon = Icon.createWithResource(mContext, R.drawable.big_a);
- Drawable d = LocalImageResolver.resolveImage(icon, mContext);
-
- assertThat(d).isInstanceOf(BitmapDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) d;
- // No isLessOrEqualThan sadly.
- assertThat(bd.getBitmap().getWidth()).isLessThan(
- LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
- assertThat(bd.getBitmap().getHeight()).isLessThan(
- LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
- }
-
- @Test
- public void resolveImage_largeResourceIcon_passedSize_resizeToDefinedSize() throws
- IOException {
- Icon icon = Icon.createWithResource(mContext, R.drawable.big_a);
- Drawable d = LocalImageResolver.resolveImage(icon, mContext, 100, 50);
-
- assertThat(d).isInstanceOf(BitmapDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) d;
- assertThat(bd.getBitmap().getWidth()).isLessThan(101);
- assertThat(bd.getBitmap().getHeight()).isLessThan(51);
- }
-
- @Test
- public void resolveImage_largeBitmapIcon_passedSize_resizeToDefinedSize() throws
- IOException {
- Icon icon = Icon.createWithBitmap(
- BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
- Drawable d = LocalImageResolver.resolveImage(icon, mContext, 100, 50);
-
- assertThat(d).isInstanceOf(BitmapDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) d;
- assertThat(bd.getBitmap().getWidth()).isLessThan(101);
- assertThat(bd.getBitmap().getHeight()).isLessThan(51);
- }
-
- @Test
- public void resolveImage_largeAdaptiveBitmapIcon_passedSize_resizeToDefinedSize() throws
- IOException {
- Icon icon = Icon.createWithAdaptiveBitmap(
- BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
- Drawable d = LocalImageResolver.resolveImage(icon, mContext, 100, 50);
-
- assertThat(d).isInstanceOf(AdaptiveIconDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) ((AdaptiveIconDrawable) d).getForeground();
- assertThat(bd.getBitmap().getWidth()).isLessThan(101);
- assertThat(bd.getBitmap().getHeight()).isLessThan(51);
- }
-
-
- @Test
- public void resolveImage_smallResourceIcon_defaultSize_untouched() throws IOException {
- Icon icon = Icon.createWithResource(mContext, R.drawable.test32x24);
- Drawable d = LocalImageResolver.resolveImage(icon, mContext);
-
- assertThat(d).isInstanceOf(BitmapDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) d;
- assertThat(bd.getBitmap().getWidth()).isEqualTo(32);
- assertThat(bd.getBitmap().getHeight()).isEqualTo(24);
- }
-
- @Test
- public void resolveImage_smallBitmapIcon_defaultSize_untouched() throws IOException {
- Icon icon = Icon.createWithBitmap(
- BitmapFactory.decodeResource(mContext.getResources(), R.drawable.test32x24));
- final int originalWidth = icon.getBitmap().getWidth();
- final int originalHeight = icon.getBitmap().getHeight();
-
- Drawable d = LocalImageResolver.resolveImage(icon, mContext);
-
- assertThat(d).isInstanceOf(BitmapDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) d;
- assertThat(bd.getBitmap().getWidth()).isEqualTo(originalWidth);
- assertThat(bd.getBitmap().getHeight()).isEqualTo(originalHeight);
- }
-
- @Test
- public void resolveImage_smallAdaptiveBitmapIcon_defaultSize_untouched() throws IOException {
- Icon icon = Icon.createWithAdaptiveBitmap(
- BitmapFactory.decodeResource(mContext.getResources(), R.drawable.test32x24));
- final int originalWidth = icon.getBitmap().getWidth();
- final int originalHeight = icon.getBitmap().getHeight();
-
- Drawable d = LocalImageResolver.resolveImage(icon, mContext);
- assertThat(d).isInstanceOf(AdaptiveIconDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) ((AdaptiveIconDrawable) d).getForeground();
- assertThat(bd.getBitmap().getWidth()).isEqualTo(originalWidth);
- assertThat(bd.getBitmap().getHeight()).isEqualTo(originalHeight);
-
- }
-}
diff --git a/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java b/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
index 5dc44d2..8de9196 100644
--- a/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
+++ b/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
@@ -123,7 +123,7 @@
public void testLogDuration() throws Exception {
TimingsTraceLog log = new TimingsTraceLog(TAG, TRACE_TAG_APP, 10);
log.logDuration("logro", 42);
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), contains("logro took to complete: 42ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), contains("logro took to complete: 42ms")));
}
@Test
@@ -134,7 +134,7 @@
verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "test"));
verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("test took to complete: \\dms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("test took to complete: \\dms")));
}
@Test
@@ -149,8 +149,8 @@
verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L2"));
verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(2)); // L1 and L2
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L2 took to complete: \\d+ms")));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L1 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
}
@Test
@@ -170,9 +170,9 @@
verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L3"));
verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(3));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L2 took to complete: \\d+ms")));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L1 took to complete: \\d+ms")));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L3 took to complete: \\d+ms")),
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L3 took to complete: \\d+ms")),
never());
verify((MockedVoidMethod) () -> Slog.w(TAG, "not tracing duration of 'L3' "
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 2a82d8e..df51871 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -71,14 +71,6 @@
}
prebuilt_etc {
- name: "privapp_whitelist_com.android.cellbroadcastreceiver",
- system_ext_specific: true,
- sub_dir: "permissions",
- src: "com.android.cellbroadcastreceiver.xml",
- filename_from_src: true,
-}
-
-prebuilt_etc {
name: "privapp_whitelist_com.android.contacts",
product_specific: true,
sub_dir: "permissions",
diff --git a/data/etc/com.android.cellbroadcastreceiver.xml b/data/etc/com.android.cellbroadcastreceiver.xml
deleted file mode 100644
index bc62bbc..0000000
--- a/data/etc/com.android.cellbroadcastreceiver.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<permissions>
- <privapp-permissions package="com.android.cellbroadcastreceiver">
- <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- <permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.STATUS_BAR"/>
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- <permission name="android.permission.MODIFY_CELL_BROADCASTS"/>
- <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
- <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
- <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
- </privapp-permissions>
-</permissions>
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 2d1db71..d1873a0 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -76,8 +76,5 @@
<permission name="android.permission.FORCE_STOP_PACKAGES" />
<permission name="android.permission.ACCESS_FPS_COUNTER" />
<permission name="android.permission.CHANGE_CONFIGURATION" />
- <permission name="android.permission.LOG_COMPAT_CHANGE" />
- <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
- <permission name="android.permission.READ_DEVICE_CONFIG" />
</privapp-permissions>
</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 3e91eed..5628548 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -38,24 +38,6 @@
<permission name="android.permission.CRYPT_KEEPER"/>
</privapp-permissions>
- <privapp-permissions package="com.android.cellbroadcastreceiver.module">
- <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- <permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.STATUS_BAR"/>
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- <permission name="android.permission.MODIFY_CELL_BROADCASTS"/>
- <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
- <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
- <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
- </privapp-permissions>
-
- <privapp-permissions package="com.android.cellbroadcastservice">
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
- <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
- </privapp-permissions>
-
<privapp-permissions package="com.android.externalstorage">
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index e898f57..4449c48 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2257,6 +2257,12 @@
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/TransitionController.java"
},
+ "264036181": {
+ "message": "Unable to retrieve task to start recording for display %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"269576220": {
"message": "Resuming rotation after drag",
"level": "DEBUG",
@@ -2761,6 +2767,12 @@
"group": "WM_DEBUG_WALLPAPER",
"at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
},
+ "736003885": {
+ "message": "Unable to retrieve the task token to start recording for display %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"736692676": {
"message": "Config is relaunching %s",
"level": "VERBOSE",
@@ -2791,6 +2803,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
+ "778774915": {
+ "message": "Unable to record task since feature is disabled %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"781471998": {
"message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s",
"level": "WARN",
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 7e68bc0..1a522bd 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -291,6 +291,14 @@
}
/**
+ * @return {@code true} if the rectangle is valid (left <= right and top <= bottom).
+ * @hide
+ */
+ public boolean isValid() {
+ return left <= right && top <= bottom;
+ }
+
+ /**
* @return the rectangle's width. This does not check for a valid rectangle
* (i.e. left <= right) so the result may be negative.
*/
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 61f7fac..a2f5301 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -329,7 +329,7 @@
FontFamily.Builder familyBuilder = null;
for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) {
final Font.Builder fontBuilder = new Font.Builder(mgr, fontFile.getFileName(),
- false /* isAsset */, 0 /* cookie */)
+ false /* isAsset */, AssetManager.COOKIE_UNKNOWN)
.setTtcIndex(fontFile.getTtcIndex())
.setFontVariationSettings(fontFile.getVariationSettings());
if (fontFile.getWeight() != Typeface.RESOLVE_BY_FONT_TABLE) {
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index cd7936d..abd0be9 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -179,7 +179,7 @@
*/
public Builder(@NonNull AssetManager am, @NonNull String path) {
try {
- mBuffer = createBuffer(am, path, true /* is asset */, 0 /* cookie */);
+ mBuffer = createBuffer(am, path, true /* is asset */, AssetManager.COOKIE_UNKNOWN);
} catch (IOException e) {
mException = e;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 1d2b938..2aa6953 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -501,7 +501,7 @@
final TaskFragmentContainer container = getContainerWithActivity(
activity.getActivityToken());
// Don't launch placeholder if the container is occluded.
- if (container != getTopActiveContainer()) {
+ if (container != null && container != getTopActiveContainer()) {
return false;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 5246117..daba774 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -532,7 +532,9 @@
}
private int getSmallestWidthDp(Rect bounds) {
- final int minWidth = Math.min(bounds.width(), bounds.height());
+ mTempRect.set(bounds);
+ mTempRect.inset(getDisplayInsets(mContext));
+ final int minWidth = Math.min(mTempRect.width(), mTempRect.height());
final float density = mContext.getResources().getDisplayMetrics().density;
return (int) (minWidth / density);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index b2bbafe..99b32a6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -42,6 +42,7 @@
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.compatui.CompatUIWindowManager.CompatUIHintsState;
import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
+import com.android.wm.shell.transition.Transitions;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -50,6 +51,8 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
+import dagger.Lazy;
+
/**
* Controller to show/update compat UI components on Tasks based on whether the foreground
* activities are in compatibility mode.
@@ -102,6 +105,7 @@
private final DisplayImeController mImeController;
private final SyncTransactionQueue mSyncQueue;
private final ShellExecutor mMainExecutor;
+ private final Lazy<Transitions> mTransitionsLazy;
private final CompatUIImpl mImpl = new CompatUIImpl();
private CompatUICallback mCallback;
@@ -118,13 +122,15 @@
DisplayInsetsController displayInsetsController,
DisplayImeController imeController,
SyncTransactionQueue syncQueue,
- ShellExecutor mainExecutor) {
+ ShellExecutor mainExecutor,
+ Lazy<Transitions> transitionsLazy) {
mContext = context;
mDisplayController = displayController;
mDisplayInsetsController = displayInsetsController;
mImeController = imeController;
mSyncQueue = syncQueue;
mMainExecutor = mainExecutor;
+ mTransitionsLazy = transitionsLazy;
mDisplayController.addDisplayWindowListener(this);
mImeController.addPositionProcessor(this);
mCompatUIHintsState = new CompatUIHintsState();
@@ -302,6 +308,7 @@
ShellTaskOrganizer.TaskListener taskListener) {
return new LetterboxEduWindowManager(context, taskInfo,
mSyncQueue, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId),
+ mTransitionsLazy.get(),
this::onLetterboxEduDismissed);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
index 03986ee..3061eab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
@@ -18,6 +18,7 @@
import static com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
import static com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
+import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -42,7 +43,9 @@
class LetterboxEduAnimationController {
private static final String TAG = "LetterboxEduAnimation";
- private static final int ENTER_ANIM_START_DELAY_MILLIS = 500;
+ // If shell transitions are enabled, startEnterAnimation will be called after all transitions
+ // have finished, and therefore the start delay should be shorter.
+ private static final int ENTER_ANIM_START_DELAY_MILLIS = ENABLE_SHELL_TRANSITIONS ? 300 : 500;
private final TransitionAnimation mTransitionAnimation;
private final String mPackageName;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
index 8aa4d0e..2e0b09e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
@@ -38,6 +38,7 @@
// The alpha of a background is a number between 0 (fully transparent) to 255 (fully opaque).
// 204 is simply 255 * 0.8.
static final int BACKGROUND_DIM_ALPHA = 204;
+
private View mDialogContainer;
private TextView mDialogTitle;
private Drawable mBackgroundDim;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
index dda72ff..cc3a3b2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
@@ -36,6 +36,7 @@
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.compatui.CompatUIWindowManagerAbstract;
+import com.android.wm.shell.transition.Transitions;
/**
* Window manager for the Letterbox Education.
@@ -63,6 +64,8 @@
private final LetterboxEduAnimationController mAnimationController;
+ private final Transitions mTransitions;
+
// Remember the last reported state in case visibility changes due to keyguard or IME updates.
private boolean mEligibleForLetterboxEducation;
@@ -80,17 +83,19 @@
public LetterboxEduWindowManager(Context context, TaskInfo taskInfo,
SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
- DisplayLayout displayLayout, Runnable onDismissCallback) {
- this(context, taskInfo, syncQueue, taskListener, displayLayout, onDismissCallback,
- new LetterboxEduAnimationController(context));
+ DisplayLayout displayLayout, Transitions transitions,
+ Runnable onDismissCallback) {
+ this(context, taskInfo, syncQueue, taskListener, displayLayout, transitions,
+ onDismissCallback, new LetterboxEduAnimationController(context));
}
@VisibleForTesting
LetterboxEduWindowManager(Context context, TaskInfo taskInfo,
SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
- DisplayLayout displayLayout, Runnable onDismissCallback,
+ DisplayLayout displayLayout, Transitions transitions, Runnable onDismissCallback,
LetterboxEduAnimationController animationController) {
super(context, taskInfo, syncQueue, taskListener, displayLayout);
+ mTransitions = transitions;
mOnDismissCallback = onDismissCallback;
mAnimationController = animationController;
mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation;
@@ -132,8 +137,8 @@
mLayout = inflateLayout();
updateDialogMargins();
- mAnimationController.startEnterAnimation(mLayout, /* endCallback= */
- this::onDialogEnterAnimationEnded);
+ // startEnterAnimation will be called immediately if shell-transitions are disabled.
+ mTransitions.runOnIdle(this::startEnterAnimation);
return mLayout;
}
@@ -158,8 +163,18 @@
R.layout.letterbox_education_dialog_layout, null);
}
+ private void startEnterAnimation() {
+ if (mLayout == null) {
+ // Dialog has already been released.
+ return;
+ }
+ mAnimationController.startEnterAnimation(mLayout, /* endCallback= */
+ this::onDialogEnterAnimationEnded);
+ }
+
private void onDialogEnterAnimationEnded() {
if (mLayout == null) {
+ // Dialog has already been released.
return;
}
mLayout.setDismissOnClickListener(this::onDismiss);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index bf0337d..1ee9407 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -96,6 +96,7 @@
import java.util.Optional;
import dagger.BindsOptionalOf;
+import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
@@ -210,9 +211,9 @@
static CompatUIController provideCompatUIController(Context context,
DisplayController displayController, DisplayInsetsController displayInsetsController,
DisplayImeController imeController, SyncTransactionQueue syncQueue,
- @ShellMainThread ShellExecutor mainExecutor) {
+ @ShellMainThread ShellExecutor mainExecutor, Lazy<Transitions> transitionsLazy) {
return new CompatUIController(context, displayController, displayInsetsController,
- imeController, syncQueue, mainExecutor);
+ imeController, syncQueue, mainExecutor, transitionsLazy);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index c2d5823..7397e52 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -194,7 +194,7 @@
public float getAspectRatioOrDefault(
@android.annotation.Nullable PictureInPictureParams params) {
return params != null && params.hasSetAspectRatio()
- ? params.getAspectRatio()
+ ? params.getAspectRatioFloat()
: getDefaultAspectRatio();
}
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 c1e7825..5d6b041 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
@@ -1071,13 +1071,13 @@
*/
private boolean applyPictureInPictureParams(@NonNull PictureInPictureParams params) {
final Rational currentAspectRatio =
- mPictureInPictureParams != null ? mPictureInPictureParams.getAspectRatioRational()
+ mPictureInPictureParams != null ? mPictureInPictureParams.getAspectRatio()
: null;
final boolean aspectRatioChanged = !Objects.equals(currentAspectRatio,
- params.getAspectRatioRational());
+ params.getAspectRatio());
mPictureInPictureParams = params;
if (aspectRatioChanged) {
- mPipBoundsState.setAspectRatio(params.getAspectRatio());
+ mPipBoundsState.setAspectRatio(params.getAspectRatioFloat());
}
return aspectRatioChanged;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
index d880f82..9865548 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
@@ -75,7 +75,7 @@
public void setBoundsStateForEntry(ComponentName componentName, ActivityInfo activityInfo,
PictureInPictureParams params, PipBoundsAlgorithm pipBoundsAlgorithm) {
super.setBoundsStateForEntry(componentName, activityInfo, params, pipBoundsAlgorithm);
- setDesiredTvExpandedAspectRatio(params.getExpandedAspectRatio(), true);
+ setDesiredTvExpandedAspectRatio(params.getExpandedAspectRatioFloat(), true);
}
/** Resets the TV PiP state for a new activity. */
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 e88eef9..177b4a8 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
@@ -24,6 +24,7 @@
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -32,6 +33,7 @@
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
@@ -68,6 +70,7 @@
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ExternalThread;
+import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
import com.android.wm.shell.recents.RecentTasksController;
@@ -196,11 +199,12 @@
@Nullable
public ActivityManager.RunningTaskInfo getTaskInfo(@SplitPosition int splitPosition) {
- if (isSplitScreenVisible()) {
- int taskId = mStageCoordinator.getTaskId(splitPosition);
- return mTaskOrganizer.getRunningTaskInfo(taskId);
+ if (!isSplitScreenVisible() || splitPosition == SPLIT_POSITION_UNDEFINED) {
+ return null;
}
- return null;
+
+ final int taskId = mStageCoordinator.getTaskId(splitPosition);
+ return mTaskOrganizer.getRunningTaskInfo(taskId);
}
public boolean isTaskInSplitScreen(int taskId) {
@@ -350,6 +354,18 @@
IRemoteAnimationFinishedCallback finishedCallback,
SurfaceControl.Transaction t) {
if (apps == null || apps.length == 0) {
+ final ActivityManager.RunningTaskInfo pairedTaskInfo =
+ getTaskInfo(SplitLayout.reversePosition(position));
+ final ComponentName pairedActivity =
+ pairedTaskInfo != null ? pairedTaskInfo.baseActivity : null;
+ final ComponentName intentActivity =
+ intent.getIntent() != null ? intent.getIntent().getComponent() : null;
+ if (pairedActivity != null && pairedActivity.equals(intentActivity)) {
+ // Switch split position if dragging the same activity to another side.
+ setSideStagePosition(SplitLayout.reversePosition(
+ mStageCoordinator.getSideStagePosition()));
+ }
+
// Do nothing when the animation was cancelled.
t.apply();
return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index fb3cd87..435d670 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -109,6 +109,9 @@
/** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
+ /** List of {@link Runnable} instances to run when the last active transition has finished. */
+ private final ArrayList<Runnable> mRunWhenIdleQueue = new ArrayList<>();
+
private float mTransitionAnimationScaleSetting = 1.0f;
private static final class ActiveTransition {
@@ -224,6 +227,21 @@
mRemoteTransitionHandler.removeFiltered(remoteTransition);
}
+ /**
+ * Runs the given {@code runnable} when the last active transition has finished, or immediately
+ * if there are currently no active transitions.
+ *
+ * <p>This method should be called on the Shell main-thread, where the given {@code runnable}
+ * will be executed when the last active transition is finished.
+ */
+ public void runOnIdle(Runnable runnable) {
+ if (mActiveTransitions.isEmpty()) {
+ runnable.run();
+ } else {
+ mRunWhenIdleQueue.add(runnable);
+ }
+ }
+
/** @return true if the transition was triggered by opening something vs closing something */
public static boolean isOpeningType(@WindowManager.TransitionType int type) {
return type == TRANSIT_OPEN
@@ -520,6 +538,11 @@
if (mActiveTransitions.size() <= activeIdx) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "All active transition animations "
+ "finished");
+ // Run all runnables from the run-when-idle queue.
+ for (int i = 0; i < mRunWhenIdleQueue.size(); i++) {
+ mRunWhenIdleQueue.get(i).run();
+ }
+ mRunWhenIdleQueue.clear();
return;
}
// Start animating the next active transition
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index a31b287..4607d8a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -53,6 +53,7 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
+import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
import org.junit.Test;
@@ -62,6 +63,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import dagger.Lazy;
+
/**
* Tests for {@link CompatUIController}.
*
@@ -82,6 +85,7 @@
private @Mock ShellTaskOrganizer.TaskListener mMockTaskListener;
private @Mock SyncTransactionQueue mMockSyncQueue;
private @Mock ShellExecutor mMockExecutor;
+ private @Mock Lazy<Transitions> mMockTransitionsLazy;
private @Mock CompatUIWindowManager mMockCompatLayout;
private @Mock LetterboxEduWindowManager mMockLetterboxEduLayout;
@@ -102,7 +106,8 @@
doReturn(true).when(mMockLetterboxEduLayout).createLayout(anyBoolean());
doReturn(true).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean());
mController = new CompatUIController(mContext, mMockDisplayController,
- mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor) {
+ mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor,
+ mMockTransitionsLazy) {
@Override
CompatUIWindowManager createCompatUiWindowManager(Context context, TaskInfo taskInfo,
ShellTaskOrganizer.TaskListener taskListener) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
index 337b738..7d51b52 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
@@ -54,6 +54,7 @@
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.transition.Transitions;
import org.junit.After;
import org.junit.Before;
@@ -86,11 +87,14 @@
private ArgumentCaptor<WindowManager.LayoutParams> mWindowAttrsCaptor;
@Captor
private ArgumentCaptor<Runnable> mEndCallbackCaptor;
+ @Captor
+ private ArgumentCaptor<Runnable> mRunOnIdleCaptor;
@Mock private LetterboxEduAnimationController mAnimationController;
@Mock private SyncTransactionQueue mSyncTransactionQueue;
@Mock private ShellTaskOrganizer.TaskListener mTaskListener;
@Mock private SurfaceControlViewHost mViewHost;
+ @Mock private Transitions mTransitions;
@Mock private Runnable mOnDismissCallback;
private SharedPreferences mSharedPreferences;
@@ -204,6 +208,23 @@
}
@Test
+ public void testCreateLayout_windowManagerReleasedBeforeTransitionsIsIdle_doesNotStartAnim() {
+ LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true);
+
+ assertTrue(windowManager.createLayout(/* canShow= */ true));
+
+ assertTrue(mSharedPreferences.getBoolean(mPrefKey, /* default= */ false));
+
+ verify(mTransitions).runOnIdle(mRunOnIdleCaptor.capture());
+
+ windowManager.release();
+
+ mRunOnIdleCaptor.getValue().run();
+
+ verify(mAnimationController, never()).startEnterAnimation(any(), any());
+ }
+
+ @Test
public void testUpdateCompatInfo_updatesLayoutCorrectly() {
LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true);
@@ -303,6 +324,13 @@
}
private void verifyAndFinishEnterAnimation(LetterboxEduDialogLayout layout) {
+ verify(mTransitions).runOnIdle(mRunOnIdleCaptor.capture());
+
+ // startEnterAnimation isn't called until run-on-idle runnable is called.
+ verify(mAnimationController, never()).startEnterAnimation(any(), any());
+
+ mRunOnIdleCaptor.getValue().run();
+
verify(mAnimationController).startEnterAnimation(eq(layout), mEndCallbackCaptor.capture());
mEndCallbackCaptor.getValue().run();
}
@@ -320,7 +348,8 @@
boolean isTaskbarEduShowing) {
LetterboxEduWindowManager windowManager = new LetterboxEduWindowManager(mContext,
createTaskInfo(eligible), mSyncTransactionQueue, mTaskListener,
- createDisplayLayout(), mOnDismissCallback, mAnimationController);
+ createDisplayLayout(), mTransitions, mOnDismissCallback,
+ mAnimationController);
spyOn(windowManager);
doReturn(mViewHost).when(windowManager).createSurfaceViewHost();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index dbf93b4..a0b1297 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -46,6 +46,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -93,7 +94,7 @@
* Tests for the shell transitions.
*
* Build/Install/Run:
- * atest WMShellUnitTests:ShellTransitionTests
+ * atest WMShellUnitTests:ShellTransitionTests
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -600,6 +601,83 @@
assertTrue(DefaultTransitionHandler.isRotationSeamless(seamlessDisplay, displays));
}
+ @Test
+ public void testRunWhenIdle() {
+ Transitions transitions = createTestTransitions();
+ transitions.replaceDefaultHandlerForTest(mDefaultHandler);
+
+ Runnable runnable1 = mock(Runnable.class);
+ Runnable runnable2 = mock(Runnable.class);
+ Runnable runnable3 = mock(Runnable.class);
+ Runnable runnable4 = mock(Runnable.class);
+
+ transitions.runOnIdle(runnable1);
+
+ // runnable1 is executed immediately because there are no active transitions.
+ verify(runnable1, times(1)).run();
+
+ clearInvocations(runnable1);
+
+ IBinder transitToken1 = new Binder();
+ transitions.requestStartTransition(transitToken1,
+ new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
+ TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+ transitions.onTransitionReady(transitToken1, info1, mock(SurfaceControl.Transaction.class),
+ mock(SurfaceControl.Transaction.class));
+ assertEquals(1, mDefaultHandler.activeCount());
+
+ transitions.runOnIdle(runnable2);
+ transitions.runOnIdle(runnable3);
+
+ // runnable2 and runnable3 aren't executed immediately because there is an active
+ // transaction.
+
+ IBinder transitToken2 = new Binder();
+ transitions.requestStartTransition(transitToken2,
+ new TransitionRequestInfo(TRANSIT_CLOSE, null /* trigger */, null /* remote */));
+ TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE)
+ .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+ transitions.onTransitionReady(transitToken2, info2, mock(SurfaceControl.Transaction.class),
+ mock(SurfaceControl.Transaction.class));
+ assertEquals(1, mDefaultHandler.activeCount());
+
+ mDefaultHandler.finishAll();
+ mMainExecutor.flushAll();
+ // first transition finished
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any(), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any(), any());
+ // But now the "queued" transition is running
+ assertEquals(1, mDefaultHandler.activeCount());
+
+ // runnable2 and runnable3 are still not executed because the second transition is still
+ // active.
+ verify(runnable2, times(0)).run();
+ verify(runnable3, times(0)).run();
+
+ mDefaultHandler.finishAll();
+ mMainExecutor.flushAll();
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any(), any());
+
+ // runnable2 and runnable3 are executed after the second transition finishes because there
+ // are no other active transitions, runnable1 isn't executed again.
+ verify(runnable1, times(0)).run();
+ verify(runnable2, times(1)).run();
+ verify(runnable3, times(1)).run();
+
+ clearInvocations(runnable2);
+ clearInvocations(runnable3);
+
+ transitions.runOnIdle(runnable4);
+
+ // runnable4 is executed immediately because there are no active transitions, all other
+ // runnables aren't executed again.
+ verify(runnable1, times(0)).run();
+ verify(runnable2, times(0)).run();
+ verify(runnable3, times(0)).run();
+ verify(runnable4, times(1)).run();
+ }
+
class TransitionInfoBuilder {
final TransitionInfo mInfo;
@@ -749,7 +827,7 @@
IWindowManager mockWM = mock(IWindowManager.class);
final IDisplayWindowListener[] displayListener = new IDisplayWindowListener[1];
try {
- doReturn(new int[] {DEFAULT_DISPLAY}).when(mockWM).registerDisplayWindowListener(any());
+ doReturn(new int[]{DEFAULT_DISPLAY}).when(mockWM).registerDisplayWindowListener(any());
} catch (RemoteException e) {
// No remote stuff happening, so this can't be hit
}
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index dd272cd..c24cabb 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -310,6 +310,11 @@
return has101012Support;
}
+bool HardwareBitmapUploader::hasAlpha8Support() {
+ static bool hasAlpha8Support = checkSupport(AHARDWAREBUFFER_FORMAT_R8_UNORM);
+ return hasAlpha8Support;
+}
+
static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
FormatInfo formatInfo;
switch (skBitmap.info().colorType()) {
@@ -363,6 +368,13 @@
}
formatInfo.format = GL_RGBA;
break;
+ case kAlpha_8_SkColorType:
+ formatInfo.isSupported = HardwareBitmapUploader::hasAlpha8Support();
+ formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
+ formatInfo.format = GL_R8;
+ formatInfo.type = GL_UNSIGNED_BYTE;
+ formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
+ break;
default:
ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
formatInfo.valid = false;
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 34f43cd..81057a2 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -30,11 +30,13 @@
#ifdef __ANDROID__
static bool hasFP16Support();
static bool has1010102Support();
+ static bool hasAlpha8Support();
#else
static bool hasFP16Support() {
return true;
}
static bool has1010102Support() { return true; }
+ static bool hasAlpha8Support() { return true; }
#endif
};
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 1a89cfd..67f4758 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -104,6 +104,10 @@
sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
+ if (bitmap.colorType() == kAlpha_8_SkColorType &&
+ !uirenderer::HardwareBitmapUploader::hasAlpha8Support()) {
+ return nullptr;
+ }
return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
#else
return Bitmap::allocateHeapBitmap(bitmap.info());
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 8c98c72..2357dfe 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -133,6 +133,7 @@
}
void DrawFrameTask::postAndWait() {
+ ATRACE_CALL();
AutoMutex _lock(mLock);
mRenderThread->queue().post([this]() { run(); });
mSignal.wait(mLock);
diff --git a/location/java/android/location/GnssExcessPathInfo.java b/location/java/android/location/GnssExcessPathInfo.java
new file mode 100644
index 0000000..72b2374
--- /dev/null
+++ b/location/java/android/location/GnssExcessPathInfo.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_ATTENUATION;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_REFLECTING_PLANE;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * Contains the info of an excess path signal caused by reflection
+ *
+ * @hide
+ */
+@SystemApi
+public final class GnssExcessPathInfo implements Parcelable {
+
+ private static final int HAS_EXCESS_PATH_LENGTH_MASK = EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH;
+ private static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK =
+ EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC;
+ private static final int HAS_REFLECTING_PLANE_MASK = EXCESS_PATH_INFO_HAS_REFLECTING_PLANE;
+ private static final int HAS_ATTENUATION_MASK = EXCESS_PATH_INFO_HAS_ATTENUATION;
+
+ /* A bitmask of fields present in this object (see HAS_* constants defined above) */
+ private final int mFlags;
+ private final float mExcessPathLengthMeters;
+ private final float mExcessPathLengthUncertaintyMeters;
+ @Nullable
+ private final GnssReflectingPlane mReflectingPlane;
+ private final float mAttenuationDb;
+
+ private GnssExcessPathInfo(
+ int flags,
+ float excessPathLengthMeters,
+ float excessPathLengthUncertaintyMeters,
+ @Nullable GnssReflectingPlane reflectingPlane,
+ float attenuationDb) {
+ mFlags = flags;
+ mExcessPathLengthMeters = excessPathLengthMeters;
+ mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+ mReflectingPlane = reflectingPlane;
+ mAttenuationDb = attenuationDb;
+ }
+
+ /**
+ * Gets a bitmask of fields present in this object.
+ *
+ * <p>This API exists for JNI since it is easier for JNI to get one integer flag than looking up
+ * several has* methods.
+ * @hide
+ */
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
+ public boolean hasExcessPathLength() {
+ return (mFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0;
+ }
+
+ /**
+ * Returns the excess path length to be subtracted from pseudorange before using it in
+ * calculating location.
+ *
+ * <p>{@link #hasExcessPathLength()} must be true when calling this method. Otherwise, an
+ * {@link UnsupportedOperationException} will be thrown.
+ */
+ @FloatRange(from = 0.0f)
+ public float getExcessPathLengthMeters() {
+ if (!hasExcessPathLength()) {
+ throw new UnsupportedOperationException(
+ "getExcessPathLengthMeters() is not supported when hasExcessPathLength() is "
+ + "false");
+ }
+ return mExcessPathLengthMeters;
+ }
+
+ /** Returns {@code true} if {@link #getExcessPathLengthUncertaintyMeters()} is valid. */
+ public boolean hasExcessPathLengthUncertainty() {
+ return (mFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
+ }
+
+ /**
+ * Returns the error estimate (1-sigma) for the excess path length estimate.
+ *
+ * <p>{@link #hasExcessPathLengthUncertainty()} must be true when calling this method.
+ * Otherwise, an {@link UnsupportedOperationException} will be thrown.
+ */
+ @FloatRange(from = 0.0f)
+ public float getExcessPathLengthUncertaintyMeters() {
+ if (!hasExcessPathLengthUncertainty()) {
+ throw new UnsupportedOperationException(
+ "getExcessPathLengthUncertaintyMeters() is not supported when "
+ + "hasExcessPathLengthUncertainty() is false");
+ }
+ return mExcessPathLengthUncertaintyMeters;
+ }
+
+ /**
+ * Returns {@code true} if {@link #getReflectingPlane()} is valid.
+ *
+ * <p>Returns false if the satellite signal goes through multiple reflections or if reflection
+ * plane serving is not supported.
+ */
+ public boolean hasReflectingPlane() {
+ return (mFlags & HAS_REFLECTING_PLANE_MASK) != 0;
+ }
+
+ /**
+ * Returns the reflecting plane characteristics at which the signal has bounced.
+ *
+ * <p>{@link #hasReflectingPlane()} must be true when calling this method. Otherwise, an
+ * {@link UnsupportedOperationException} will be thrown.
+ */
+ @NonNull
+ public GnssReflectingPlane getReflectingPlane() {
+ if (!hasReflectingPlane()) {
+ throw new UnsupportedOperationException(
+ "getReflectingPlane() is not supported when hasReflectingPlane() is false");
+ }
+ return mReflectingPlane;
+ }
+
+ /** Returns {@code true} if {@link #getAttenuationDb()} is valid. */
+ public boolean hasAttenuation() {
+ return (mFlags & HAS_ATTENUATION_MASK) != 0;
+ }
+
+ /**
+ * Returns the expected reduction of signal strength of this path in non-negative dB.
+ *
+ * <p>{@link #hasAttenuation()} must be true when calling this method. Otherwise, an
+ * {@link UnsupportedOperationException} will be thrown.
+ */
+ @FloatRange(from = 0.0f)
+ public float getAttenuationDb() {
+ if (!hasAttenuation()) {
+ throw new UnsupportedOperationException(
+ "getAttenuationDb() is not supported when hasAttenuation() is false");
+ }
+ return mAttenuationDb;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int parcelFlags) {
+ parcel.writeInt(mFlags);
+ if (hasExcessPathLength()) {
+ parcel.writeFloat(mExcessPathLengthMeters);
+ }
+ if (hasExcessPathLengthUncertainty()) {
+ parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
+ }
+ if (hasReflectingPlane()) {
+ mReflectingPlane.writeToParcel(parcel, parcelFlags);
+ }
+ if (hasAttenuation()) {
+ parcel.writeFloat(mAttenuationDb);
+ }
+ }
+
+ public static final @NonNull Creator<GnssExcessPathInfo> CREATOR =
+ new Creator<GnssExcessPathInfo>() {
+ @Override
+ @NonNull
+ public GnssExcessPathInfo createFromParcel(@NonNull Parcel parcel) {
+ int flags = parcel.readInt();
+ float excessPathLengthMeters =
+ (flags & HAS_EXCESS_PATH_LENGTH_MASK) != 0
+ ? parcel.readFloat() : 0;
+ float excessPathLengthUncertaintyMeters =
+ (flags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0
+ ? parcel.readFloat() : 0;
+ GnssReflectingPlane reflectingPlane =
+ (flags & HAS_REFLECTING_PLANE_MASK) != 0
+ ? GnssReflectingPlane.CREATOR.createFromParcel(parcel) : null;
+ float attenuationDb =
+ (flags & HAS_ATTENUATION_MASK) != 0
+ ? parcel.readFloat() : 0;
+ return new GnssExcessPathInfo(flags, excessPathLengthMeters,
+ excessPathLengthUncertaintyMeters, reflectingPlane, attenuationDb);
+ }
+
+ @Override
+ public GnssExcessPathInfo[] newArray(int i) {
+ return new GnssExcessPathInfo[i];
+ }
+ };
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof GnssExcessPathInfo) {
+ GnssExcessPathInfo that = (GnssExcessPathInfo) obj;
+ return this.mFlags == that.mFlags
+ && (!hasExcessPathLength() || Float.compare(this.mExcessPathLengthMeters,
+ that.mExcessPathLengthMeters) == 0)
+ && (!hasExcessPathLengthUncertainty() || Float.compare(
+ this.mExcessPathLengthUncertaintyMeters,
+ that.mExcessPathLengthUncertaintyMeters) == 0)
+ && (!hasReflectingPlane() || Objects.equals(this.mReflectingPlane,
+ that.mReflectingPlane))
+ && (!hasAttenuation() || Float.compare(this.mAttenuationDb,
+ that.mAttenuationDb) == 0);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFlags,
+ mExcessPathLengthMeters,
+ mExcessPathLengthUncertaintyMeters,
+ mReflectingPlane,
+ mAttenuationDb);
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("GnssExcessPathInfo[");
+ if (hasExcessPathLength()) {
+ builder.append(" ExcessPathLengthMeters=").append(mExcessPathLengthMeters);
+ }
+ if (hasExcessPathLengthUncertainty()) {
+ builder.append(" ExcessPathLengthUncertaintyMeters=").append(
+ mExcessPathLengthUncertaintyMeters);
+ }
+ if (hasReflectingPlane()) {
+ builder.append(" ReflectingPlane=").append(mReflectingPlane);
+ }
+ if (hasAttenuation()) {
+ builder.append(" AttenuationDb=").append(mAttenuationDb);
+ }
+ builder.append(']');
+ return builder.toString();
+ }
+
+ /** Builder for {@link GnssExcessPathInfo}. */
+ public static final class Builder {
+ private int mFlags;
+ private float mExcessPathLengthMeters;
+ private float mExcessPathLengthUncertaintyMeters;
+ @Nullable
+ private GnssReflectingPlane mReflectingPlane;
+ private float mAttenuationDb;
+
+ /** Constructor for {@link Builder}. */
+ public Builder() {}
+
+ /**
+ * Sets the excess path length to be subtracted from pseudorange before using it in
+ * calculating location.
+ */
+ @NonNull
+ public Builder setExcessPathLengthMeters(
+ @FloatRange(from = 0.0f) float excessPathLengthMeters) {
+ Preconditions.checkArgumentInRange(excessPathLengthMeters, 0, Float.MAX_VALUE,
+ "excessPathLengthMeters");
+ mExcessPathLengthMeters = excessPathLengthMeters;
+ mFlags |= HAS_EXCESS_PATH_LENGTH_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the excess path length.
+ *
+ * <p>This is to negate {@link #setExcessPathLengthMeters} call.
+ */
+ @NonNull
+ public Builder clearExcessPathLengthMeters() {
+ mExcessPathLengthMeters = 0;
+ mFlags &= ~HAS_EXCESS_PATH_LENGTH_MASK;
+ return this;
+ }
+
+ /** Sets the error estimate (1-sigma) for the excess path length estimate */
+ @NonNull
+ public Builder setExcessPathLengthUncertaintyMeters(
+ @FloatRange(from = 0.0f) float excessPathLengthUncertaintyMeters) {
+ Preconditions.checkArgumentInRange(excessPathLengthUncertaintyMeters, 0,
+ Float.MAX_VALUE, "excessPathLengthUncertaintyMeters");
+ mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+ mFlags |= HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the error estimate (1-sigma) for the excess path length estimate
+ *
+ * <p>This is to negate {@link #setExcessPathLengthUncertaintyMeters} call.
+ */
+ @NonNull
+ public Builder clearExcessPathLengthUncertaintyMeters() {
+ mExcessPathLengthUncertaintyMeters = 0;
+ mFlags &= ~HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ return this;
+ }
+
+ /** Sets the reflecting plane information */
+ @NonNull
+ public Builder setReflectingPlane(@Nullable GnssReflectingPlane reflectingPlane) {
+ mReflectingPlane = reflectingPlane;
+ if (reflectingPlane != null) {
+ mFlags |= HAS_REFLECTING_PLANE_MASK;
+ } else {
+ mFlags &= ~HAS_REFLECTING_PLANE_MASK;
+ }
+ return this;
+ }
+
+ /**
+ * Sets the attenuation value in dB.
+ */
+ @NonNull
+ public Builder setAttenuationDb(@FloatRange(from = 0.0f) float attenuationDb) {
+ Preconditions.checkArgumentInRange(attenuationDb, 0, Float.MAX_VALUE,
+ "attenuationDb");
+ mAttenuationDb = attenuationDb;
+ mFlags |= HAS_ATTENUATION_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the attenuation value in dB.
+ *
+ * <p>This is to negate {@link #setAttenuationDb(float)} call.
+ */
+ @NonNull
+ public Builder clearAttenuationDb() {
+ mAttenuationDb = 0;
+ mFlags &= ~HAS_ATTENUATION_MASK;
+ return this;
+ }
+
+ /** Builds a {@link GnssExcessPathInfo} instance as specified by this builder. */
+ @NonNull
+ public GnssExcessPathInfo build() {
+ return new GnssExcessPathInfo(
+ mFlags,
+ mExcessPathLengthMeters,
+ mExcessPathLengthUncertaintyMeters,
+ mReflectingPlane,
+ mAttenuationDb);
+ }
+ }
+}
diff --git a/location/java/android/location/GnssReflectingPlane.java b/location/java/android/location/GnssReflectingPlane.java
index 1acdd1e..115cbec 100644
--- a/location/java/android/location/GnssReflectingPlane.java
+++ b/location/java/android/location/GnssReflectingPlane.java
@@ -22,9 +22,14 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* Holds the characteristics of the reflecting plane that a satellite signal has bounced from.
*
+ * <p>Starting with Android T, this class supports {@link #equals} and {@link #hashCode}, which
+ * are not supported before that.
+ *
* @hide
*/
@SystemApi
@@ -107,18 +112,6 @@
}
};
- @NonNull
- @Override
- public String toString() {
- final String format = " %-29s = %s\n";
- StringBuilder builder = new StringBuilder("ReflectingPlane:\n");
- builder.append(String.format(format, "LatitudeDegrees = ", mLatitudeDegrees));
- builder.append(String.format(format, "LongitudeDegrees = ", mLongitudeDegrees));
- builder.append(String.format(format, "AltitudeMeters = ", mAltitudeMeters));
- builder.append(String.format(format, "AzimuthDegrees = ", mAzimuthDegrees));
- return builder.toString();
- }
-
@Override
public void writeToParcel(@NonNull Parcel parcel, int flags) {
parcel.writeDouble(mLatitudeDegrees);
@@ -127,6 +120,35 @@
parcel.writeDouble(mAzimuthDegrees);
}
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("ReflectingPlane[");
+ builder.append(" LatitudeDegrees=").append(mLatitudeDegrees);
+ builder.append(" LongitudeDegrees=").append(mLongitudeDegrees);
+ builder.append(" AltitudeMeters=").append(mAltitudeMeters);
+ builder.append(" AzimuthDegrees=").append(mAzimuthDegrees);
+ builder.append(']');
+ return builder.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof GnssReflectingPlane) {
+ GnssReflectingPlane that = (GnssReflectingPlane) obj;
+ return Double.compare(this.mLatitudeDegrees, that.mLatitudeDegrees) == 0
+ && Double.compare(this.mLongitudeDegrees, that.mLongitudeDegrees) == 0
+ && Double.compare(this.mAltitudeMeters, that.mAltitudeMeters) == 0
+ && Double.compare(this.mAzimuthDegrees, that.mAzimuthDegrees) == 0;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mLatitudeDegrees, mLatitudeDegrees, mAltitudeMeters, mAzimuthDegrees);
+ }
+
/** Builder for {@link GnssReflectingPlane} */
public static final class Builder {
/** For documentation, see corresponding fields in {@link GnssReflectingPlane}. */
diff --git a/location/java/android/location/GnssSingleSatCorrection.java b/location/java/android/location/GnssSingleSatCorrection.java
index 262630b..a7fce0a 100644
--- a/location/java/android/location/GnssSingleSatCorrection.java
+++ b/location/java/android/location/GnssSingleSatCorrection.java
@@ -16,6 +16,11 @@
package android.location;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY;
+
import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -26,6 +31,8 @@
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
/**
@@ -36,106 +43,47 @@
@SystemApi
public final class GnssSingleSatCorrection implements Parcelable {
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mProbSatIsLos}.
- *
- * @hide
- */
- public static final int HAS_PROB_SAT_IS_LOS_MASK = 1 << 0;
+ private static final int HAS_PROB_SAT_IS_LOS_MASK =
+ SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY;
+ private static final int HAS_COMBINED_EXCESS_PATH_LENGTH_MASK =
+ SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH;
+ private static final int HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK =
+ SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC;
+ private static final int HAS_COMBINED_ATTENUATION_MASK =
+ SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mExcessPathLengthMeters}.
- *
- * @hide
- */
- public static final int HAS_EXCESS_PATH_LENGTH_MASK = 1 << 1;
-
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mExcessPathLengthUncertaintyMeters}.
- *
- * @hide
- */
- public static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK = 1 << 2;
-
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mReflectingPlane}.
- *
- * @hide
- */
- public static final int HAS_REFLECTING_PLANE_MASK = 1 << 3;
-
- /** A bitmask of fields present in this object (see HAS_* constants defined above) */
+ /* A bitmask of fields present in this object (see HAS_* constants defined above). */
private final int mSingleSatCorrectionFlags;
- /** Defines the constellation of the given satellite as defined in {@link GnssStatus}. */
- @GnssStatus.ConstellationType
private final int mConstellationType;
-
- /**
- * Satellite vehicle ID number
- *
- * <p>Interpretation depends on {@link GnssStatus#getSvid(int)}.
- */
- @IntRange(from = 0)
private final int mSatId;
-
- /**
- * Carrier frequency of the signal to be corrected, for example it can be the GPS center
- * frequency for L1 = 1,575,420,000 Hz, varying GLO channels, etc.
- *
- * <p>For an L1, L5 receiver tracking a satellite on L1 and L5 at the same time, two correction
- * objects will be reported for this same satellite, in one of the correction objects, all the
- * values related to L1 will be filled, and in the other all of the values related to L5 will be
- * filled.
- */
- @FloatRange(from = 0.0f, fromInclusive = false)
private final float mCarrierFrequencyHz;
-
- /**
- * The probability that the satellite is estimated to be in Line-of-Sight condition at the given
- * location.
- */
- @FloatRange(from = 0.0f, to = 1.0f)
private final float mProbSatIsLos;
+ private final float mCombinedExcessPathLengthMeters;
+ private final float mCombinedExcessPathLengthUncertaintyMeters;
+ private final float mCombinedAttenuationDb;
- /**
- * Excess path length to be subtracted from pseudorange before using it in calculating location.
- */
- @FloatRange(from = 0.0f)
- private final float mExcessPathLengthMeters;
-
- /** Error estimate (1-sigma) for the Excess path length estimate */
- @FloatRange(from = 0.0f)
- private final float mExcessPathLengthUncertaintyMeters;
-
- /**
- * Defines the reflecting plane location and azimuth information
- *
- * <p>The flag HAS_REFLECTING_PLANE will be used to set this value to invalid if the satellite
- * signal goes through multiple reflections or if reflection plane serving is not supported.
- */
- @Nullable
- private final GnssReflectingPlane mReflectingPlane;
+ @NonNull
+ private final List<GnssExcessPathInfo> mGnssExcessPathInfoList;
private GnssSingleSatCorrection(int singleSatCorrectionFlags, int constellationType, int satId,
float carrierFrequencyHz, float probSatIsLos, float excessPathLengthMeters,
- float excessPathLengthUncertaintyMeters, GnssReflectingPlane reflectingPlane) {
+ float excessPathLengthUncertaintyMeters,
+ float combinedAttenuationDb,
+ @NonNull List<GnssExcessPathInfo> gnssExcessPathInfoList) {
mSingleSatCorrectionFlags = singleSatCorrectionFlags;
mConstellationType = constellationType;
mSatId = satId;
mCarrierFrequencyHz = carrierFrequencyHz;
mProbSatIsLos = probSatIsLos;
- mExcessPathLengthMeters = excessPathLengthMeters;
- mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
- mReflectingPlane = reflectingPlane;
+ mCombinedExcessPathLengthMeters = excessPathLengthMeters;
+ mCombinedExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+ mCombinedAttenuationDb = combinedAttenuationDb;
+ mGnssExcessPathInfoList = gnssExcessPathInfoList;
}
/**
- * Gets a bitmask of fields present in this object
+ * Gets a bitmask of fields present in this object.
*
* @hide
*/
@@ -193,29 +141,46 @@
}
/**
- * Returns the Excess path length to be subtracted from pseudorange before using it in
+ * Returns the combined excess path length to be subtracted from pseudorange before using it in
* calculating location.
*/
@FloatRange(from = 0.0f)
public float getExcessPathLengthMeters() {
- return mExcessPathLengthMeters;
+ return mCombinedExcessPathLengthMeters;
}
- /** Returns the error estimate (1-sigma) for the Excess path length estimate */
+ /** Returns the error estimate (1-sigma) for the combined excess path length estimate. */
@FloatRange(from = 0.0f)
public float getExcessPathLengthUncertaintyMeters() {
- return mExcessPathLengthUncertaintyMeters;
+ return mCombinedExcessPathLengthUncertaintyMeters;
}
/**
- * Returns the reflecting plane characteristics at which the signal has bounced
+ * Returns the combined expected reduction of signal strength for this satellite in
+ * non-negative dB.
+ */
+ @FloatRange(from = 0.0f)
+ public float getCombinedAttenuationDb() {
+ return mCombinedAttenuationDb;
+ }
+
+ /**
+ * Returns the reflecting plane characteristics at which the signal has bounced.
*
- * <p>The flag HAS_REFLECTING_PLANE will be used to set this value to invalid if the satellite
- * signal goes through multiple reflections or if reflection plane serving is not supported
+ * @deprecated Combined excess path does not have a reflecting plane.
*/
@Nullable
+ @Deprecated
public GnssReflectingPlane getReflectingPlane() {
- return mReflectingPlane;
+ return null;
+ }
+
+ /**
+ * Returns the list of {@link GnssExcessPathInfo} associated with this satellite signal.
+ */
+ @NonNull
+ public List<GnssExcessPathInfo> getGnssExcessPathInfoList() {
+ return mGnssExcessPathInfoList;
}
/** Returns {@code true} if {@link #getProbabilityLineOfSight()} is valid. */
@@ -225,17 +190,27 @@
/** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
public boolean hasExcessPathLength() {
- return (mSingleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0;
+ return (mSingleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_MASK) != 0;
}
/** Returns {@code true} if {@link #getExcessPathLengthUncertaintyMeters()} is valid. */
public boolean hasExcessPathLengthUncertainty() {
- return (mSingleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
+ return (mSingleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
}
- /** Returns {@code true} if {@link #getReflectingPlane()} is valid. */
+ /**
+ * Returns {@code true} if {@link #getReflectingPlane()} is valid.
+ *
+ * @deprecated Combined excess path does not have a reflecting plane.
+ */
+ @Deprecated
public boolean hasReflectingPlane() {
- return (mSingleSatCorrectionFlags & HAS_REFLECTING_PLANE_MASK) != 0;
+ return false;
+ }
+
+ /** Returns {@code true} if {@link #getCombinedAttenuationDb()} is valid. */
+ public boolean hasCombinedAttenuation() {
+ return (mSingleSatCorrectionFlags & HAS_COMBINED_ATTENUATION_MASK) != 0;
}
@Override
@@ -253,14 +228,15 @@
parcel.writeFloat(mProbSatIsLos);
}
if (hasExcessPathLength()) {
- parcel.writeFloat(mExcessPathLengthMeters);
+ parcel.writeFloat(mCombinedExcessPathLengthMeters);
}
if (hasExcessPathLengthUncertainty()) {
- parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
+ parcel.writeFloat(mCombinedExcessPathLengthUncertaintyMeters);
}
- if (hasReflectingPlane()) {
- mReflectingPlane.writeToParcel(parcel, flags);
+ if (hasCombinedAttenuation()) {
+ parcel.writeFloat(mCombinedAttenuationDb);
}
+ parcel.writeTypedList(mGnssExcessPathInfoList);
}
public static final Creator<GnssSingleSatCorrection> CREATOR =
@@ -274,18 +250,21 @@
float carrierFrequencyHz = parcel.readFloat();
float probSatIsLos = (singleSatCorrectionFlags & HAS_PROB_SAT_IS_LOS_MASK) != 0
? parcel.readFloat() : 0;
- float excessPathLengthMeters =
- (singleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0
+ float combinedExcessPathLengthMeters =
+ (singleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_MASK) != 0
? parcel.readFloat() : 0;
- float excessPathLengthUncertaintyMeters =
- (singleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0
+ float combinedExcessPathLengthUncertaintyMeters =
+ (singleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK)
+ != 0 ? parcel.readFloat() : 0;
+ float combinedAttenuationDb =
+ (singleSatCorrectionFlags & HAS_COMBINED_ATTENUATION_MASK) != 0
? parcel.readFloat() : 0;
- GnssReflectingPlane reflectingPlane =
- (singleSatCorrectionFlags & HAS_REFLECTING_PLANE_MASK) != 0
- ? GnssReflectingPlane.CREATOR.createFromParcel(parcel) : null;
+ List<GnssExcessPathInfo> gnssExcessPathInfoList = parcel.createTypedArrayList(
+ GnssExcessPathInfo.CREATOR);
return new GnssSingleSatCorrection(singleSatCorrectionFlags, constellationType,
- satId, carrierFrequencyHz, probSatIsLos, excessPathLengthMeters,
- excessPathLengthUncertaintyMeters, reflectingPlane);
+ satId, carrierFrequencyHz, probSatIsLos, combinedExcessPathLengthMeters,
+ combinedExcessPathLengthUncertaintyMeters, combinedAttenuationDb,
+ gnssExcessPathInfoList);
}
@Override
@@ -296,56 +275,24 @@
@Override
public boolean equals(Object obj) {
- if (this == obj) {
- return true;
+ if (obj instanceof GnssSingleSatCorrection) {
+ GnssSingleSatCorrection that = (GnssSingleSatCorrection) obj;
+ return this.mSingleSatCorrectionFlags == that.mSingleSatCorrectionFlags
+ && this.mConstellationType == that.mConstellationType
+ && this.mSatId == that.mSatId
+ && Float.compare(mCarrierFrequencyHz, that.mCarrierFrequencyHz) == 0
+ && (!hasValidSatelliteLineOfSight() || Float.compare(mProbSatIsLos,
+ that.mProbSatIsLos) == 0)
+ && (!hasExcessPathLength() || Float.compare(mCombinedExcessPathLengthMeters,
+ that.mCombinedExcessPathLengthMeters) == 0)
+ && (!hasExcessPathLengthUncertainty() || Float.compare(
+ mCombinedExcessPathLengthUncertaintyMeters,
+ that.mCombinedExcessPathLengthUncertaintyMeters) == 0)
+ && (!hasCombinedAttenuation() || Float.compare(mCombinedAttenuationDb,
+ that.mCombinedAttenuationDb) == 0)
+ && mGnssExcessPathInfoList.equals(that.mGnssExcessPathInfoList);
}
- if (!(obj instanceof GnssSingleSatCorrection)) {
- return false;
- }
-
- GnssSingleSatCorrection other = (GnssSingleSatCorrection) obj;
- if (mConstellationType != other.mConstellationType) {
- return false;
- }
- if (mSatId != other.mSatId) {
- return false;
- }
- if (Float.compare(mCarrierFrequencyHz, other.mCarrierFrequencyHz) != 0) {
- return false;
- }
-
- if (hasValidSatelliteLineOfSight() != other.hasValidSatelliteLineOfSight()) {
- return false;
- }
- if (hasValidSatelliteLineOfSight()
- && Float.compare(mProbSatIsLos, other.mProbSatIsLos) != 0) {
- return false;
- }
-
- if (hasExcessPathLength() != other.hasExcessPathLength()) {
- return false;
- }
- if (hasExcessPathLength()
- && Float.compare(mExcessPathLengthMeters, other.mExcessPathLengthMeters) != 0) {
- return false;
- }
-
- if (hasExcessPathLengthUncertainty() != other.hasExcessPathLengthUncertainty()) {
- return false;
- }
- if (hasExcessPathLengthUncertainty() && Float.compare(mExcessPathLengthUncertaintyMeters,
- other.mExcessPathLengthUncertaintyMeters) != 0) {
- return false;
- }
-
- if (hasReflectingPlane() != other.hasReflectingPlane()) {
- return false;
- }
- if (hasReflectingPlane()
- && !mReflectingPlane.equals(other.mReflectingPlane)) {
- return false;
- }
- return true;
+ return false;
}
@Override
@@ -355,9 +302,10 @@
mSatId,
mCarrierFrequencyHz,
mProbSatIsLos,
- mExcessPathLengthMeters,
- mExcessPathLengthUncertaintyMeters,
- mReflectingPlane);
+ mCombinedExcessPathLengthMeters,
+ mCombinedExcessPathLengthUncertaintyMeters,
+ mCombinedAttenuationDb,
+ mGnssExcessPathInfoList);
}
@NonNull
@@ -371,14 +319,19 @@
builder.append(" ProbSatIsLos=").append(mProbSatIsLos);
}
if (hasExcessPathLength()) {
- builder.append(" ExcessPathLengthMeters=").append(mExcessPathLengthMeters);
+ builder.append(" CombinedExcessPathLengthMeters=").append(
+ mCombinedExcessPathLengthMeters);
}
if (hasExcessPathLengthUncertainty()) {
- builder.append(" ExcessPathLengthUncertaintyMeters=").append(
- mExcessPathLengthUncertaintyMeters);
+ builder.append(" CombinedExcessPathLengthUncertaintyMeters=").append(
+ mCombinedExcessPathLengthUncertaintyMeters);
}
- if (hasReflectingPlane()) {
- builder.append(" ReflectingPlane=").append(mReflectingPlane);
+ if (hasCombinedAttenuation()) {
+ builder.append(" CombinedAttenuationDb=").append(
+ mCombinedAttenuationDb);
+ }
+ if (!mGnssExcessPathInfoList.isEmpty()) {
+ builder.append(' ').append(mGnssExcessPathInfoList.toString());
}
builder.append(']');
return builder.toString();
@@ -386,21 +339,16 @@
/** Builder for {@link GnssSingleSatCorrection} */
public static final class Builder {
-
- /**
- * For documentation of below fields, see corresponding fields in {@link
- * GnssSingleSatCorrection}.
- */
private int mSingleSatCorrectionFlags;
-
private int mConstellationType;
private int mSatId;
private float mCarrierFrequencyHz;
private float mProbSatIsLos;
- private float mExcessPathLengthMeters;
- private float mExcessPathLengthUncertaintyMeters;
- @Nullable
- private GnssReflectingPlane mReflectingPlane;
+ private float mCombinedExcessPathLengthMeters;
+ private float mCombinedExcessPathLengthUncertaintyMeters;
+ private float mCombinedAttenuationDb;
+ @NonNull
+ private List<GnssExcessPathInfo> mGnssExcessInfoList = new ArrayList<>();
/** Sets the constellation type. */
@NonNull public Builder setConstellationType(
@@ -409,18 +357,18 @@
return this;
}
- /** Sets the Satellite ID defined in the ICD of the given constellation. */
+ /** Sets the satellite ID defined in the ICD of the given constellation. */
@NonNull public Builder setSatelliteId(@IntRange(from = 0) int satId) {
Preconditions.checkArgumentNonnegative(satId, "satId should be non-negative.");
mSatId = satId;
return this;
}
- /** Sets the Carrier frequency in Hz. */
+ /** Sets the carrier frequency in Hz. */
@NonNull public Builder setCarrierFrequencyHz(
@FloatRange(from = 0.0f, fromInclusive = false) float carrierFrequencyHz) {
- Preconditions.checkArgument(
- carrierFrequencyHz >= 0, "carrierFrequencyHz should be non-negative.");
+ Preconditions.checkArgumentInRange(
+ carrierFrequencyHz, 0, Float.MAX_VALUE, "carrierFrequencyHz");
mCarrierFrequencyHz = carrierFrequencyHz;
return this;
}
@@ -450,58 +398,90 @@
}
/**
- * Sets the Excess path length to be subtracted from pseudorange before using it in
+ * Sets the combined excess path length to be subtracted from pseudorange before using it in
* calculating location.
*/
- @NonNull public Builder setExcessPathLengthMeters(
- @FloatRange(from = 0.0f) float excessPathLengthMeters) {
- Preconditions.checkArgument(excessPathLengthMeters >= 0,
- "excessPathLengthMeters should be non-negative.");
- mExcessPathLengthMeters = excessPathLengthMeters;
- mSingleSatCorrectionFlags |= HAS_EXCESS_PATH_LENGTH_MASK;
+ @NonNull
+ public Builder setExcessPathLengthMeters(
+ @FloatRange(from = 0.0f) float combinedExcessPathLengthMeters) {
+ Preconditions.checkArgumentInRange(combinedExcessPathLengthMeters, 0, Float.MAX_VALUE,
+ "excessPathLengthMeters");
+ mCombinedExcessPathLengthMeters = combinedExcessPathLengthMeters;
+ mSingleSatCorrectionFlags |= HAS_COMBINED_EXCESS_PATH_LENGTH_MASK;
return this;
}
/**
- * Clears the Excess path length.
+ * Clears the combined excess path length.
*
* <p>This is to negate {@link #setExcessPathLengthMeters} call.
*/
@NonNull public Builder clearExcessPathLengthMeters() {
- mExcessPathLengthMeters = 0;
- mSingleSatCorrectionFlags &= ~HAS_EXCESS_PATH_LENGTH_MASK;
+ mCombinedExcessPathLengthMeters = 0;
+ mSingleSatCorrectionFlags &= ~HAS_COMBINED_EXCESS_PATH_LENGTH_MASK;
return this;
}
- /** Sets the error estimate (1-sigma) for the Excess path length estimate */
+ /** Sets the error estimate (1-sigma) for the combined excess path length estimate. */
@NonNull public Builder setExcessPathLengthUncertaintyMeters(
- @FloatRange(from = 0.0f) float excessPathLengthUncertaintyMeters) {
- Preconditions.checkArgument(excessPathLengthUncertaintyMeters >= 0,
- "excessPathLengthUncertaintyMeters should be non-negative.");
- mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
- mSingleSatCorrectionFlags |= HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ @FloatRange(from = 0.0f) float combinedExcessPathLengthUncertaintyMeters) {
+ Preconditions.checkArgumentInRange(combinedExcessPathLengthUncertaintyMeters, 0,
+ Float.MAX_VALUE, "excessPathLengthUncertaintyMeters");
+ mCombinedExcessPathLengthUncertaintyMeters = combinedExcessPathLengthUncertaintyMeters;
+ mSingleSatCorrectionFlags |= HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK;
return this;
}
/**
- * Clears the error estimate (1-sigma) for the Excess path length estimate
+ * Clears the error estimate (1-sigma) for the combined excess path length estimate.
*
* <p>This is to negate {@link #setExcessPathLengthUncertaintyMeters} call.
*/
@NonNull public Builder clearExcessPathLengthUncertaintyMeters() {
- mExcessPathLengthUncertaintyMeters = 0;
- mSingleSatCorrectionFlags &= ~HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ mCombinedExcessPathLengthUncertaintyMeters = 0;
+ mSingleSatCorrectionFlags &= ~HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK;
return this;
}
- /** Sets the reflecting plane information */
+ /**
+ * Sets the combined attenuation in Db.
+ */
+ @NonNull public Builder setCombinedAttenuationDb(
+ @FloatRange(from = 0.0f) float combinedAttenuationDb) {
+ Preconditions.checkArgumentInRange(combinedAttenuationDb, 0, Float.MAX_VALUE,
+ "combinedAttenuationDb");
+ mCombinedAttenuationDb = combinedAttenuationDb;
+ mSingleSatCorrectionFlags |= HAS_COMBINED_ATTENUATION_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the combined attenuation.
+ *
+ * <p>This is to negate {@link #setCombinedAttenuationDb} call.
+ */
+ @NonNull public Builder clearCombinedAttenuationDb() {
+ mCombinedAttenuationDb = 0;
+ mSingleSatCorrectionFlags &= ~HAS_COMBINED_ATTENUATION_MASK;
+ return this;
+ }
+
+ /**
+ * Sets the reflecting plane information.
+ *
+ * @deprecated Combined excess path does not have a reflecting plane.
+ */
+ @Deprecated
@NonNull public Builder setReflectingPlane(@Nullable GnssReflectingPlane reflectingPlane) {
- mReflectingPlane = reflectingPlane;
- if (reflectingPlane != null) {
- mSingleSatCorrectionFlags |= HAS_REFLECTING_PLANE_MASK;
- } else {
- mSingleSatCorrectionFlags &= ~HAS_REFLECTING_PLANE_MASK;
- }
+ return this;
+ }
+
+ /**
+ * Sets the collection of {@link GnssExcessPathInfo}.
+ */
+ @NonNull
+ public Builder setGnssExcessPathInfoList(@NonNull List<GnssExcessPathInfo> infoList) {
+ mGnssExcessInfoList = new ArrayList<>(infoList);
return this;
}
@@ -512,9 +492,10 @@
mSatId,
mCarrierFrequencyHz,
mProbSatIsLos,
- mExcessPathLengthMeters,
- mExcessPathLengthUncertaintyMeters,
- mReflectingPlane);
+ mCombinedExcessPathLengthMeters,
+ mCombinedExcessPathLengthUncertaintyMeters,
+ mCombinedAttenuationDb,
+ mGnssExcessInfoList);
}
}
}
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index f1605f1..033056c 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -132,31 +132,31 @@
}
/**
- * Construct a new Location object that is copied from an existing one.
+ * Constructs a new location copied from the given location.
*/
- public Location(@NonNull Location l) {
- set(l);
+ public Location(@NonNull Location location) {
+ set(location);
}
/**
* Turns this location into a copy of the given location.
*/
- public void set(@NonNull Location l) {
- mFieldsMask = l.mFieldsMask;
- mProvider = l.mProvider;
- mTimeMs = l.mTimeMs;
- mElapsedRealtimeNs = l.mElapsedRealtimeNs;
- mElapsedRealtimeUncertaintyNs = l.mElapsedRealtimeUncertaintyNs;
- mLatitudeDegrees = l.mLatitudeDegrees;
- mLongitudeDegrees = l.mLongitudeDegrees;
- mHorizontalAccuracyMeters = l.mHorizontalAccuracyMeters;
- mAltitudeMeters = l.mAltitudeMeters;
- mAltitudeAccuracyMeters = l.mAltitudeAccuracyMeters;
- mSpeedMetersPerSecond = l.mSpeedMetersPerSecond;
- mSpeedAccuracyMetersPerSecond = l.mSpeedAccuracyMetersPerSecond;
- mBearingDegrees = l.mBearingDegrees;
- mBearingAccuracyDegrees = l.mBearingAccuracyDegrees;
- mExtras = (l.mExtras == null) ? null : new Bundle(l.mExtras);
+ public void set(@NonNull Location location) {
+ mFieldsMask = location.mFieldsMask;
+ mProvider = location.mProvider;
+ mTimeMs = location.mTimeMs;
+ mElapsedRealtimeNs = location.mElapsedRealtimeNs;
+ mElapsedRealtimeUncertaintyNs = location.mElapsedRealtimeUncertaintyNs;
+ mLatitudeDegrees = location.mLatitudeDegrees;
+ mLongitudeDegrees = location.mLongitudeDegrees;
+ mHorizontalAccuracyMeters = location.mHorizontalAccuracyMeters;
+ mAltitudeMeters = location.mAltitudeMeters;
+ mAltitudeAccuracyMeters = location.mAltitudeAccuracyMeters;
+ mSpeedMetersPerSecond = location.mSpeedMetersPerSecond;
+ mSpeedAccuracyMetersPerSecond = location.mSpeedAccuracyMetersPerSecond;
+ mBearingDegrees = location.mBearingDegrees;
+ mBearingAccuracyDegrees = location.mBearingAccuracyDegrees;
+ mExtras = (location.mExtras == null) ? null : new Bundle(location.mExtras);
}
/**
@@ -182,14 +182,13 @@
}
/**
- * Returns the approximate distance in meters between this
- * location and the given location. Distance is defined using
- * the WGS84 ellipsoid.
+ * Returns the approximate distance in meters between this location and the given location.
+ * Distance is defined using the WGS84 ellipsoid.
*
* @param dest the destination location
* @return the approximate distance in meters
*/
- public @FloatRange float distanceTo(@NonNull Location dest) {
+ public @FloatRange(from = 0.0) float distanceTo(@NonNull Location dest) {
BearingDistanceCache cache = sBearingDistanceCache.get();
// See if we already have the result
if (mLatitudeDegrees != cache.mLat1 || mLongitudeDegrees != cache.mLon1
@@ -201,11 +200,10 @@
}
/**
- * Returns the approximate initial bearing in degrees East of true
- * North when traveling along the shortest path between this
- * location and the given location. The shortest path is defined
- * using the WGS84 ellipsoid. Locations that are (nearly)
- * antipodal may produce meaningless results.
+ * Returns the approximate initial bearing in degrees east of true north when traveling along
+ * the shortest path between this location and the given location. The shortest path is defined
+ * using the WGS84 ellipsoid. Locations that are (nearly) antipodal may produce meaningless
+ * results.
*
* @param dest the destination location
* @return the initial bearing in degrees
@@ -254,7 +252,7 @@
* not be used to order or compare locations. Prefer {@link #getElapsedRealtimeNanos} for that
* purpose, as the elapsed realtime clock is guaranteed to be monotonic.
*
- * <p>On the other hand, this method may be useful for presenting a human readable time to the
+ * <p>On the other hand, this method may be useful for presenting a human-readable time to the
* user, or as a heuristic for comparing location fixes across reboot or across devices.
*
* <p>All locations generated by the {@link LocationManager} are guaranteed to have this time
@@ -263,25 +261,24 @@
*
* @return the Unix epoch time of this location
*/
- public @IntRange long getTime() {
+ public @IntRange(from = 0) long getTime() {
return mTimeMs;
}
/**
* Sets the Unix epoch time of this location fix, in milliseconds since the start of the Unix
- * epoch (00:00:00 January 1, 1970 UTC).
+ * epoch (00:00:00 January 1 1970 UTC).
*
* @param timeMs the Unix epoch time of this location
- * @see #getTime for more information about times / clocks
*/
- public void setTime(@IntRange long timeMs) {
+ public void setTime(@IntRange(from = 0) long timeMs) {
mTimeMs = timeMs;
}
/**
* Return the time of this fix in nanoseconds of elapsed realtime since system boot.
*
- * <p>This value can be compared with {@link android.os.SystemClock#elapsedRealtimeNanos}, to
+ * <p>This value can be compared with {@link android.os.SystemClock#elapsedRealtimeNanos} to
* reliably order or compare locations. This is reliable because elapsed realtime is guaranteed
* to be monotonic and continues to increment even when the system is in deep sleep (unlike
* {@link #getTime}). However, since elapsed realtime is with reference to system boot, it does
@@ -292,7 +289,7 @@
*
* @return elapsed realtime of this location in nanoseconds
*/
- public @IntRange long getElapsedRealtimeNanos() {
+ public @IntRange(from = 0) long getElapsedRealtimeNanos() {
return mElapsedRealtimeNs;
}
@@ -302,7 +299,7 @@
* @return elapsed realtime of this location in milliseconds
* @see #getElapsedRealtimeNanos()
*/
- public @IntRange long getElapsedRealtimeMillis() {
+ public @IntRange(from = 0) long getElapsedRealtimeMillis() {
return NANOSECONDS.toMillis(mElapsedRealtimeNs);
}
@@ -312,7 +309,7 @@
*
* @return age of this location in milliseconds
*/
- public @IntRange long getElapsedRealtimeAgeMillis() {
+ public @IntRange(from = 0) long getElapsedRealtimeAgeMillis() {
return getElapsedRealtimeAgeMillis(SystemClock.elapsedRealtime());
}
@@ -323,7 +320,8 @@
* @param referenceRealtimeMs reference realtime in milliseconds
* @return age of this location in milliseconds
*/
- public @IntRange long getElapsedRealtimeAgeMillis(@IntRange long referenceRealtimeMs) {
+ public long getElapsedRealtimeAgeMillis(
+ @IntRange(from = 0) long referenceRealtimeMs) {
return referenceRealtimeMs - getElapsedRealtimeMillis();
}
@@ -332,7 +330,7 @@
*
* @param elapsedRealtimeNs elapsed realtime in nanoseconds
*/
- public void setElapsedRealtimeNanos(@IntRange long elapsedRealtimeNs) {
+ public void setElapsedRealtimeNanos(@IntRange(from = 0) long elapsedRealtimeNs) {
mElapsedRealtimeNs = elapsedRealtimeNs;
}
@@ -346,7 +344,7 @@
*
* @return uncertainty in nanoseconds of the elapsed realtime of this location
*/
- public @FloatRange double getElapsedRealtimeUncertaintyNanos() {
+ public @FloatRange(from = 0.0) double getElapsedRealtimeUncertaintyNanos() {
return mElapsedRealtimeUncertaintyNs;
}
@@ -358,20 +356,20 @@
* this location
*/
public void setElapsedRealtimeUncertaintyNanos(
- @FloatRange double elapsedRealtimeUncertaintyNs) {
+ @FloatRange(from = 0.0) double elapsedRealtimeUncertaintyNs) {
mElapsedRealtimeUncertaintyNs = elapsedRealtimeUncertaintyNs;
mFieldsMask |= HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK;
}
/**
- * True if this location has a elapsed realtime uncertainty, false otherwise.
+ * True if this location has an elapsed realtime uncertainty, false otherwise.
*/
public boolean hasElapsedRealtimeUncertaintyNanos() {
return (mFieldsMask & HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK) != 0;
}
/**
- * Removes the elapsed realtime uncertainy from this location.
+ * Removes the elapsed realtime uncertainty from this location.
*/
public void removeElapsedRealtimeUncertaintyNanos() {
mFieldsMask &= ~HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK;
@@ -383,7 +381,7 @@
*
* @return latitude of this location
*/
- public @FloatRange double getLatitude() {
+ public @FloatRange(from = -90.0, to = 90.0) double getLatitude() {
return mLatitudeDegrees;
}
@@ -392,7 +390,7 @@
*
* @param latitudeDegrees latitude in degrees
*/
- public void setLatitude(@FloatRange double latitudeDegrees) {
+ public void setLatitude(@FloatRange(from = -90.0, to = 90.0) double latitudeDegrees) {
mLatitudeDegrees = latitudeDegrees;
}
@@ -402,7 +400,7 @@
*
* @return longitude of this location
*/
- public @FloatRange double getLongitude() {
+ public @FloatRange(from = -180.0, to = 180.0) double getLongitude() {
return mLongitudeDegrees;
}
@@ -411,7 +409,7 @@
*
* @param longitudeDegrees longitude in degrees
*/
- public void setLongitude(@FloatRange double longitudeDegrees) {
+ public void setLongitude(@FloatRange(from = -180.0, to = 180.0) double longitudeDegrees) {
mLongitudeDegrees = longitudeDegrees;
}
@@ -423,12 +421,12 @@
* reported location, there is a 68% chance that the true location falls within this circle.
* This accuracy value is only valid for horizontal positioning, and not vertical positioning.
*
- * <p>This is only valid if {@link #hasSpeed()} is true. All locations generated by the
+ * <p>This is only valid if {@link #hasAccuracy()} is true. All locations generated by the
* {@link LocationManager} include horizontal accuracy.
*
* @return horizontal accuracy of this location
*/
- public @FloatRange float getAccuracy() {
+ public @FloatRange(from = 0.0) float getAccuracy() {
return mHorizontalAccuracyMeters;
}
@@ -437,7 +435,7 @@
*
* @param horizontalAccuracyMeters horizontal altitude in meters
*/
- public void setAccuracy(@FloatRange float horizontalAccuracyMeters) {
+ public void setAccuracy(@FloatRange(from = 0.0) float horizontalAccuracyMeters) {
mHorizontalAccuracyMeters = horizontalAccuracyMeters;
mFieldsMask |= HAS_HORIZONTAL_ACCURACY_MASK;
}
@@ -500,7 +498,7 @@
*
* @return vertical accuracy of this location
*/
- public @FloatRange float getVerticalAccuracyMeters() {
+ public @FloatRange(from = 0.0) float getVerticalAccuracyMeters() {
return mAltitudeAccuracyMeters;
}
@@ -509,7 +507,7 @@
*
* @param altitudeAccuracyMeters altitude accuracy in meters
*/
- public void setVerticalAccuracyMeters(@FloatRange float altitudeAccuracyMeters) {
+ public void setVerticalAccuracyMeters(@FloatRange(from = 0.0) float altitudeAccuracyMeters) {
mAltitudeAccuracyMeters = altitudeAccuracyMeters;
mFieldsMask |= HAS_ALTITUDE_ACCURACY_MASK;
}
@@ -538,17 +536,16 @@
*
* @return speed at the time of this location
*/
- public @FloatRange float getSpeed() {
+ public @FloatRange(from = 0.0) float getSpeed() {
return mSpeedMetersPerSecond;
}
/**
- * Set the speed at the time of this location, in meters per second. Prefer not to set negative
- * speeds.
+ * Set the speed at the time of this location, in meters per second.
*
* @param speedMetersPerSecond speed in meters per second
*/
- public void setSpeed(@FloatRange float speedMetersPerSecond) {
+ public void setSpeed(@FloatRange(from = 0.0) float speedMetersPerSecond) {
mSpeedMetersPerSecond = speedMetersPerSecond;
mFieldsMask |= HAS_SPEED_MASK;
}
@@ -576,7 +573,7 @@
*
* @return vertical accuracy of this location
*/
- public @FloatRange float getSpeedAccuracyMetersPerSecond() {
+ public @FloatRange(from = 0.0) float getSpeedAccuracyMetersPerSecond() {
return mSpeedAccuracyMetersPerSecond;
}
@@ -585,7 +582,8 @@
*
* @param speedAccuracyMeterPerSecond speed accuracy in meters per second
*/
- public void setSpeedAccuracyMetersPerSecond(@FloatRange float speedAccuracyMeterPerSecond) {
+ public void setSpeedAccuracyMetersPerSecond(
+ @FloatRange(from = 0.0) float speedAccuracyMeterPerSecond) {
mSpeedAccuracyMetersPerSecond = speedAccuracyMeterPerSecond;
mFieldsMask |= HAS_SPEED_ACCURACY_MASK;
}
@@ -613,7 +611,7 @@
*
* @return bearing at the time of this location
*/
- public @FloatRange(from = 0f, to = 360f, toInclusive = false) float getBearing() {
+ public @FloatRange(from = 0.0, to = 360.0, toInclusive = false) float getBearing() {
return mBearingDegrees;
}
@@ -663,7 +661,7 @@
*
* @return bearing accuracy in degrees of this location
*/
- public @FloatRange float getBearingAccuracyDegrees() {
+ public @FloatRange(from = 0.0) float getBearingAccuracyDegrees() {
return mBearingAccuracyDegrees;
}
@@ -672,7 +670,7 @@
*
* @param bearingAccuracyDegrees bearing accuracy in degrees
*/
- public void setBearingAccuracyDegrees(@FloatRange float bearingAccuracyDegrees) {
+ public void setBearingAccuracyDegrees(@FloatRange(from = 0.0) float bearingAccuracyDegrees) {
mBearingAccuracyDegrees = bearingAccuracyDegrees;
mFieldsMask |= HAS_BEARING_ACCURACY_MASK;
}
@@ -692,9 +690,11 @@
}
/**
- * Returns true if the Location came from a mock provider.
+ * Returns true if this is a mock location. If this location comes from the Android framework,
+ * this indicates that the location was provided by a test location provider, and thus may not
+ * be related to the actual location of the device.
*
- * @return true if this Location came from a mock provider, false otherwise
+ * @return true if this location came from a mock provider, false otherwise
* @deprecated Prefer {@link #isMock()} instead.
*/
@Deprecated
@@ -703,9 +703,9 @@
}
/**
- * Flag this Location as having come from a mock provider or not.
+ * Flag this location as having come from a mock provider or not.
*
- * @param isFromMockProvider true if this Location came from a mock provider, false otherwise
+ * @param isFromMockProvider true if this location came from a mock provider, false otherwise
* @deprecated Prefer {@link #setMock(boolean)} instead.
* @hide
*/
@@ -745,7 +745,7 @@
* will be present for any location.
*
* <ul>
- * <li> satellites - the number of satellites used to derive the GNSS fix
+ * <li> satellites - the number of satellites used to derive a GNSS fix
* </ul>
*/
public @Nullable Bundle getExtras() {
@@ -899,7 +899,13 @@
return s.toString();
}
- /** Dumps location. */
+ /**
+ * Dumps location information to the given Printer.
+ *
+ * @deprecated Prefer to use {@link #toString()} along with whatever custom formatting is
+ * required instead of this method. It is not this class's job to manage print representations.
+ */
+ @Deprecated
public void dump(@NonNull Printer pw, @Nullable String prefix) {
pw.println(prefix + this);
}
@@ -1209,10 +1215,10 @@
* @throws IllegalArgumentException if results is null or has length < 1
*/
public static void distanceBetween(
- @FloatRange double startLatitude,
- @FloatRange double startLongitude,
- @FloatRange double endLatitude,
- @FloatRange double endLongitude,
+ @FloatRange(from = -90.0, to = 90.0) double startLatitude,
+ @FloatRange(from = -180.0, to = 180.0) double startLongitude,
+ @FloatRange(from = -90.0, to = 90.0) double endLatitude,
+ @FloatRange(from = -180.0, to = 180.0) double endLongitude,
float[] results) {
if (results == null || results.length < 1) {
throw new IllegalArgumentException("results is null or has length < 1");
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index bdbb740..c186700 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -39,6 +39,7 @@
import android.media.IRingtonePlayer;
import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.ISpatializerCallback;
+import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback;
import android.media.ISpatializerOutputCallback;
@@ -414,6 +415,11 @@
boolean isHeadTrackerEnabled(in AudioDeviceAttributes device);
+ boolean isHeadTrackerAvailable();
+
+ void registerSpatializerHeadTrackerAvailableCallback(
+ in ISpatializerHeadTrackerAvailableCallback cb, boolean register);
+
void setSpatializerEnabled(boolean enabled);
boolean canBeSpatialized(in AudioAttributes aa, in AudioFormat af);
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl b/media/java/android/media/ISpatializerHeadTrackerAvailableCallback.aidl
similarity index 62%
copy from media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl
copy to media/java/android/media/ISpatializerHeadTrackerAvailableCallback.aidl
index 5e15016..dc5ee1d 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl
+++ b/media/java/android/media/ISpatializerHeadTrackerAvailableCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,14 @@
* limitations under the License.
*/
-package android.media.tv.interactive;
+package android.media;
-parcelable TvInteractiveAppInfo;
\ No newline at end of file
+/**
+ * AIDL for the AudioService to signal whether audio device used by Spatializer has head tracker.
+ *
+ * {@hide}
+ */
+oneway interface ISpatializerHeadTrackerAvailableCallback {
+
+ void dispatchSpatializerHeadTrackerAvailable(boolean available);
+}
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 4956dbe..7d3f916 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -793,8 +793,11 @@
* By default, the decoder will output the same number of channels as present in the encoded
* stream, if supported. Set this value to limit the number of output channels, and use
* the downmix information in the stream, if available.
- * <p>Values larger than the number of channels in the content to decode are ignored.
+ * <p>Values larger than the number of channels in the content to decode behave just
+ * like the actual channel count of the content (e.g. passing 99 for the decoding of 5.1 content
+ * will behave like using 6).
* <p>This key is only used during decoding.
+ * @deprecated Use the non-AAC-specific key {@link #KEY_MAX_OUTPUT_CHANNEL_COUNT} instead
*/
public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
diff --git a/media/java/android/media/Spatializer.java b/media/java/android/media/Spatializer.java
index be0ef37..74ca4b8 100644
--- a/media/java/android/media/Spatializer.java
+++ b/media/java/android/media/Spatializer.java
@@ -185,6 +185,45 @@
return false;
}
+ /**
+ * Returns whether a head tracker is currently available for the audio device used by the
+ * spatializer effect.
+ * @return true if a head tracker is available and the effect is enabled, false otherwise.
+ * @see OnHeadTrackerAvailableListener
+ * @see #addOnHeadTrackerAvailableListener(Executor, OnHeadTrackerAvailableListener)
+ */
+ public boolean isHeadTrackerAvailable() {
+ try {
+ return mAm.getService().isHeadTrackerAvailable();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
+ * Adds a listener to be notified of changes to the availability of a head tracker.
+ * @param executor the {@code Executor} handling the callback
+ * @param listener the listener to receive availability updates
+ * @see #removeOnHeadTrackerAvailableListener(OnHeadTrackerAvailableListener)
+ */
+ public void addOnHeadTrackerAvailableListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull OnHeadTrackerAvailableListener listener) {
+ mHeadTrackerListenerMgr.addListener(executor, listener,
+ "addOnHeadTrackerAvailableListener",
+ () -> new SpatializerHeadTrackerAvailableDispatcherStub());
+ }
+
+ /**
+ * Removes a previously registered listener for the availability of a head tracker.
+ * @param listener the listener previously registered with
+ * {@link #addOnHeadTrackerAvailableListener(Executor, OnHeadTrackerAvailableListener)}
+ */
+ public void removeOnHeadTrackerAvailableListener(
+ @NonNull OnHeadTrackerAvailableListener listener) {
+ mHeadTrackerListenerMgr.removeListener(listener, "removeOnHeadTrackerAvailableListener");
+ }
+
/** @hide */
@IntDef(flag = false, value = {
SPATIALIZER_IMMERSIVE_LEVEL_OTHER,
@@ -401,6 +440,22 @@
@HeadTrackingModeSet int mode);
}
+ /**
+ * Interface to be notified of changes to the availability of a head tracker on the audio
+ * device to be used by the spatializer effect.
+ */
+ public interface OnHeadTrackerAvailableListener {
+ /**
+ * Called when the availability of the head tracker changed.
+ * @param spatializer the {@code Spatializer} instance for which the head tracker
+ * availability was updated
+ * @param available true if the audio device that would output audio processed by
+ * the {@code Spatializer} has a head tracker associated with it, false
+ * otherwise.
+ */
+ void onHeadTrackerAvailableChanged(@NonNull Spatializer spatializer,
+ boolean available);
+ }
/**
* @hide
@@ -827,8 +882,12 @@
/**
* @hide
- * Returns the id of the output stream used for the spatializer effect playback
+ * Returns the id of the output stream used for the spatializer effect playback.
+ * This getter or associated listener {@link OnSpatializerOutputChangedListener} can be used for
+ * handling spatializer output-specific configurations (e.g. disabling speaker post-processing
+ * to avoid double-processing of the spatialized path).
* @return id of the output stream, or 0 if no spatializer playback is active
+ * @see #setOnSpatializerOutputChangedListener(Executor, OnSpatializerOutputChangedListener)
*/
@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
@RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
@@ -865,6 +924,8 @@
mOutputDispatcher = new SpatializerOutputDispatcherStub();
try {
mAm.getService().registerSpatializerOutputCallback(mOutputDispatcher);
+ // immediately report the current output
+ mOutputDispatcher.dispatchSpatializerOutputChanged(getOutput());
} catch (RemoteException e) {
mOutputListener = null;
mOutputDispatcher = null;
@@ -935,6 +996,36 @@
}
//-----------------------------------------------------------------------------
+ // head tracker availability callback management and stub
+ /**
+ * manages the OnHeadTrackerAvailableListener listeners and the
+ * SpatializerHeadTrackerAvailableDispatcherStub
+ */
+ private final CallbackUtil.LazyListenerManager<OnHeadTrackerAvailableListener>
+ mHeadTrackerListenerMgr = new CallbackUtil.LazyListenerManager();
+
+ private final class SpatializerHeadTrackerAvailableDispatcherStub
+ extends ISpatializerHeadTrackerAvailableCallback.Stub
+ implements CallbackUtil.DispatcherStub {
+ @Override
+ public void register(boolean register) {
+ try {
+ mAm.getService().registerSpatializerHeadTrackerAvailableCallback(this, register);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ @SuppressLint("GuardedBy") // lock applied inside callListeners method
+ public void dispatchSpatializerHeadTrackerAvailable(boolean available) {
+ mHeadTrackerListenerMgr.callListeners(
+ (listener) -> listener.onHeadTrackerAvailableChanged(
+ Spatializer.this, available));
+ }
+ }
+
+ //-----------------------------------------------------------------------------
// head pose callback management and stub
private final Object mPoseListenerLock = new Object();
/**
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl
index 19fc052..b136d5b 100644
--- a/media/java/android/media/projection/IMediaProjection.aidl
+++ b/media/java/android/media/projection/IMediaProjection.aidl
@@ -17,6 +17,7 @@
package android.media.projection;
import android.media.projection.IMediaProjectionCallback;
+import android.window.WindowContainerToken;
/** {@hide} */
interface IMediaProjection {
@@ -28,4 +29,16 @@
int applyVirtualDisplayFlags(int flags);
void registerCallback(IMediaProjectionCallback callback);
void unregisterCallback(IMediaProjectionCallback callback);
+
+ /**
+ * Returns the {@link android.window.WindowContainerToken} identifying the task to record, or
+ * {@code null} if there is none.
+ */
+ WindowContainerToken getTaskRecordingWindowContainerToken();
+
+ /**
+ * Updates the {@link android.window.WindowContainerToken} identifying the task to record, or
+ * {@code null} if there is none.
+ */
+ void setTaskRecordingWindowContainerToken(in WindowContainerToken token);
}
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 4dde5e8..b5f9593 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -25,13 +25,14 @@
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.os.Handler;
-import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
import android.view.ContentRecordingSession;
+import android.view.IWindowManager;
import android.view.Surface;
import android.view.WindowManagerGlobal;
+import android.window.WindowContainerToken;
import java.util.Map;
@@ -171,16 +172,34 @@
@NonNull VirtualDisplayConfig.Builder virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
try {
- final Context windowContext = mContext.createWindowContext(
- mContext.getDisplayNoVerify(),
- TYPE_APPLICATION, null /* options */);
- final IBinder windowContextToken = windowContext.getWindowContextToken();
+ final IWindowManager wmService = WindowManagerGlobal.getWindowManagerService();
+ final WindowContainerToken taskWindowContainerToken =
+ mImpl.getTaskRecordingWindowContainerToken();
+ Context windowContext = null;
+ ContentRecordingSession session;
+ if (taskWindowContainerToken == null) {
+ windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
+ TYPE_APPLICATION, null /* options */);
+ session = ContentRecordingSession.createDisplaySession(
+ windowContext.getWindowContextToken());
+ } else {
+ session = ContentRecordingSession.createTaskSession(
+ taskWindowContainerToken.asBinder());
+ }
virtualDisplayConfig.setWindowManagerMirroring(true);
final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
final VirtualDisplay virtualDisplay = dm.createVirtualDisplay(this,
- virtualDisplayConfig.build(),
- callback, handler, windowContext);
- setSession(windowContextToken, virtualDisplay);
+ virtualDisplayConfig.build(), callback, handler, windowContext);
+ if (virtualDisplay == null) {
+ // Since WM handling a new display and DM creating a new VirtualDisplay is async,
+ // WM may have tried to start task recording and encountered an error that required
+ // stopping recording entirely. The VirtualDisplay would then be null when the
+ // MediaProjection is no longer active.
+ return null;
+ }
+ session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
+ // Successfully set up, so save the current session details.
+ wmService.setContentRecordingSession(session);
return virtualDisplay;
} catch (RemoteException e) {
// Can not capture if WMS is not accessible, so bail out.
@@ -189,28 +208,6 @@
}
/**
- * Updates the {@link ContentRecordingSession} describing the recording taking place on this
- * {@link VirtualDisplay}.
- *
- * @throws RemoteException if updating the session on the server failed.
- */
- private void setSession(@NonNull IBinder windowContextToken,
- @Nullable VirtualDisplay virtualDisplay)
- throws RemoteException {
- if (virtualDisplay == null) {
- // Not able to set up a new VirtualDisplay.
- return;
- }
- // Identify the VirtualDisplay that will be hosting the recording.
- ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
- windowContextToken);
- session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
- // TODO(b/216625226) handle task recording.
- // Successfully set up, so save the current session details.
- WindowManagerGlobal.getWindowManagerService().setContentRecordingSession(session);
- }
-
- /**
* Stops projection.
*/
public void stop() {
diff --git a/media/java/android/media/tv/AitInfo.java b/media/java/android/media/tv/AitInfo.java
index 8e80a62..c88a2b5 100644
--- a/media/java/android/media/tv/AitInfo.java
+++ b/media/java/android/media/tv/AitInfo.java
@@ -17,7 +17,7 @@
package android.media.tv;
import android.annotation.NonNull;
-import android.media.tv.interactive.TvInteractiveAppInfo;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
import android.os.Parcel;
import android.os.Parcelable;
@@ -50,7 +50,7 @@
/**
* Constructs AIT info.
*/
- public AitInfo(@TvInteractiveAppInfo.InteractiveAppType int type, int version) {
+ public AitInfo(@TvInteractiveAppServiceInfo.InteractiveAppType int type, int version) {
mType = type;
mVersion = version;
}
@@ -58,7 +58,7 @@
/**
* Gets interactive app type.
*/
- @TvInteractiveAppInfo.InteractiveAppType
+ @TvInteractiveAppServiceInfo.InteractiveAppType
public int getType() {
return mType;
}
diff --git a/media/java/android/media/tv/CommandRequest.java b/media/java/android/media/tv/CommandRequest.java
index ffb6e07..3245fb5 100644
--- a/media/java/android/media/tv/CommandRequest.java
+++ b/media/java/android/media/tv/CommandRequest.java
@@ -24,6 +24,8 @@
* A request for command from broadcast signal.
*/
public final class CommandRequest extends BroadcastInfoRequest implements Parcelable {
+ public static final String ARGUMENT_TYPE_XML = "xml";
+ public static final String ARGUMENT_TYPE_JSON = "json";
private static final @TvInputManager.BroadcastInfoType int REQUEST_TYPE =
TvInputManager.BROADCAST_INFO_TYPE_COMMAND;
@@ -41,35 +43,38 @@
}
};
- private final String mNameSpace;
+ private final String mNamespace;
private final String mName;
private final String mArguments;
+ private final String mArgumentType;
static CommandRequest createFromParcelBody(Parcel in) {
return new CommandRequest(in);
}
- public CommandRequest(int requestId, @RequestOption int option, @NonNull String nameSpace,
- @NonNull String name, @NonNull String arguments) {
+ public CommandRequest(int requestId, @RequestOption int option, @NonNull String namespace,
+ @NonNull String name, @NonNull String arguments, @NonNull String argumentType) {
super(REQUEST_TYPE, requestId, option);
- mNameSpace = nameSpace;
+ mNamespace = namespace;
mName = name;
mArguments = arguments;
+ mArgumentType = argumentType;
}
CommandRequest(Parcel source) {
super(REQUEST_TYPE, source);
- mNameSpace = source.readString();
+ mNamespace = source.readString();
mName = source.readString();
mArguments = source.readString();
+ mArgumentType = source.readString();
}
/**
* Gets the namespace of the command.
*/
@NonNull
- public String getNameSpace() {
- return mNameSpace;
+ public String getNamespace() {
+ return mNamespace;
}
/**
@@ -89,6 +94,15 @@
return mArguments;
}
+ /**
+ * Gets the argument type of the command.
+ * It could be either JSON or XML.
+ */
+ @NonNull
+ public String getArgumentType() {
+ return mArgumentType;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -97,8 +111,9 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
- dest.writeString(mNameSpace);
+ dest.writeString(mNamespace);
dest.writeString(mName);
dest.writeString(mArguments);
+ dest.writeString(mArgumentType);
}
}
diff --git a/media/java/android/media/tv/CommandResponse.java b/media/java/android/media/tv/CommandResponse.java
index c8853f1..8e448cd 100644
--- a/media/java/android/media/tv/CommandResponse.java
+++ b/media/java/android/media/tv/CommandResponse.java
@@ -25,6 +25,8 @@
* A response for command from broadcast signal.
*/
public final class CommandResponse extends BroadcastInfoResponse implements Parcelable {
+ public static final String RESPONSE_TYPE_XML = "xml";
+ public static final String RESPONSE_TYPE_JSON = "json";
private static final @TvInputManager.BroadcastInfoType int RESPONSE_TYPE =
TvInputManager.BROADCAST_INFO_TYPE_COMMAND;
@@ -43,20 +45,23 @@
};
private final String mResponse;
+ private final String mResponseType;
static CommandResponse createFromParcelBody(Parcel in) {
return new CommandResponse(in);
}
- public CommandResponse(int requestId, int sequence,
- @ResponseResult int responseResult, @Nullable String response) {
+ public CommandResponse(int requestId, int sequence, @ResponseResult int responseResult,
+ @Nullable String response, @NonNull String responseType) {
super(RESPONSE_TYPE, requestId, sequence, responseResult);
mResponse = response;
+ mResponseType = responseType;
}
CommandResponse(Parcel source) {
super(RESPONSE_TYPE, source);
mResponse = source.readString();
+ mResponseType = source.readString();
}
/**
@@ -68,6 +73,15 @@
return mResponse;
}
+ /**
+ * Gets the type of the command response.
+ * It could be either JSON or XML.
+ */
+ @NonNull
+ public String getResponseType() {
+ return mResponseType;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -77,5 +91,6 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(mResponse);
+ dest.writeString(mResponseType);
}
}
diff --git a/media/java/android/media/tv/SectionRequest.java b/media/java/android/media/tv/SectionRequest.java
index 5957528..078e832 100644
--- a/media/java/android/media/tv/SectionRequest.java
+++ b/media/java/android/media/tv/SectionRequest.java
@@ -80,6 +80,11 @@
/**
* Gets the version number of requested session. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
diff --git a/media/java/android/media/tv/SectionResponse.java b/media/java/android/media/tv/SectionResponse.java
index 35836be..f38ea9d 100644
--- a/media/java/android/media/tv/SectionResponse.java
+++ b/media/java/android/media/tv/SectionResponse.java
@@ -74,14 +74,20 @@
}
/**
- * Gets the Version number of requested session.
+ * Gets the Version number of requested session. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
}
/**
- * Gets the raw data of session.
+ * Gets the raw data of session. The sessionData field represents payload data of the session
+ * after session header, which includes version and sessionId.
*/
@NonNull
public Bundle getSessionData() {
diff --git a/media/java/android/media/tv/StreamEventResponse.java b/media/java/android/media/tv/StreamEventResponse.java
index f952ce9..28dff37 100644
--- a/media/java/android/media/tv/StreamEventResponse.java
+++ b/media/java/android/media/tv/StreamEventResponse.java
@@ -43,7 +43,7 @@
};
private final int mEventId;
- private final long mNpt;
+ private final long mNptMillis;
private final byte[] mData;
static StreamEventResponse createFromParcelBody(Parcel in) {
@@ -51,17 +51,17 @@
}
public StreamEventResponse(int requestId, int sequence, @ResponseResult int responseResult,
- int eventId, long npt, @Nullable byte[] data) {
+ int eventId, long nptMillis, @Nullable byte[] data) {
super(RESPONSE_TYPE, requestId, sequence, responseResult);
mEventId = eventId;
- mNpt = npt;
+ mNptMillis = nptMillis;
mData = data;
}
private StreamEventResponse(@NonNull Parcel source) {
super(RESPONSE_TYPE, source);
mEventId = source.readInt();
- mNpt = source.readLong();
+ mNptMillis = source.readLong();
int dataLength = source.readInt();
mData = new byte[dataLength];
source.readByteArray(mData);
@@ -76,9 +76,10 @@
/**
* Returns the NPT(Normal Play Time) value when the event occurred or will occur.
+ * <p>The time unit of NPT is millisecond.
*/
- public long getNpt() {
- return mNpt;
+ public long getNptMillis() {
+ return mNptMillis;
}
/**
@@ -98,7 +99,7 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(mEventId);
- dest.writeLong(mNpt);
+ dest.writeLong(mNptMillis);
dest.writeInt(mData.length);
dest.writeByteArray(mData);
}
diff --git a/media/java/android/media/tv/TableRequest.java b/media/java/android/media/tv/TableRequest.java
index 37df4ea..a1a6b51 100644
--- a/media/java/android/media/tv/TableRequest.java
+++ b/media/java/android/media/tv/TableRequest.java
@@ -91,7 +91,12 @@
}
/**
- * Gets the version number of requested table.
+ * Gets the version number of requested table. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
diff --git a/media/java/android/media/tv/TableResponse.java b/media/java/android/media/tv/TableResponse.java
index e9f1136..afc9bee 100644
--- a/media/java/android/media/tv/TableResponse.java
+++ b/media/java/android/media/tv/TableResponse.java
@@ -76,7 +76,12 @@
}
/**
- * Gets the Version number of table.
+ * Gets the version number of requested table. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
diff --git a/media/java/android/media/tv/TimelineResponse.java b/media/java/android/media/tv/TimelineResponse.java
index fbeb0c4..7de30f5 100644
--- a/media/java/android/media/tv/TimelineResponse.java
+++ b/media/java/android/media/tv/TimelineResponse.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -79,8 +80,8 @@
* that conveys Time Values on it.
*/
@Nullable
- public String getSelector() {
- return mSelector;
+ public Uri getSelector() {
+ return Uri.parse(mSelector);
}
/**
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
index aaabe34..8391182 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
@@ -23,7 +23,7 @@
import android.media.tv.interactive.AppLinkInfo;
import android.media.tv.interactive.ITvInteractiveAppClient;
import android.media.tv.interactive.ITvInteractiveAppManagerCallback;
-import android.media.tv.interactive.TvInteractiveAppInfo;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
import android.net.Uri;
import android.os.Bundle;
import android.view.Surface;
@@ -33,7 +33,7 @@
* @hide
*/
interface ITvInteractiveAppManager {
- List<TvInteractiveAppInfo> getTvInteractiveAppServiceList(int userId);
+ List<TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList(int userId);
void prepare(String tiasId, int type, int userId);
void registerAppLinkInfo(String tiasId, in AppLinkInfo info, int userId);
void unregisterAppLinkInfo(String tiasId, in AppLinkInfo info, int userId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
index 23be4c6..f410c0f 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
@@ -16,7 +16,7 @@
package android.media.tv.interactive;
-import android.media.tv.interactive.TvInteractiveAppInfo;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
/**
* Interface to receive callbacks from ITvInteractiveAppManager regardless of sessions.
@@ -26,6 +26,6 @@
void onInteractiveAppServiceAdded(in String iAppServiceId);
void onInteractiveAppServiceRemoved(in String iAppServiceId);
void onInteractiveAppServiceUpdated(in String iAppServiceId);
- void onTvInteractiveAppInfoUpdated(in TvInteractiveAppInfo tvIAppInfo);
+ void onTvInteractiveAppServiceInfoUpdated(in TvInteractiveAppServiceInfo tvIAppInfo);
void onStateChanged(in String iAppServiceId, int type, int state, int err);
}
\ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index 9eb4a6c..83ff0f5 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -249,7 +249,7 @@
*
* @see #sendAppLinkCommand(String, Bundle)
* @see #ACTION_APP_LINK_COMMAND
- * @see android.media.tv.interactive.TvInteractiveAppInfo#getId()
+ * @see android.media.tv.interactive.TvInteractiveAppServiceInfo#getId()
*/
public static final String INTENT_KEY_INTERACTIVE_APP_SERVICE_ID = "interactive_app_id";
@@ -269,7 +269,7 @@
*
* @see #sendAppLinkCommand(String, Bundle)
* @see #ACTION_APP_LINK_COMMAND
- * @see android.media.tv.interactive.TvInteractiveAppInfo#getSupportedTypes()
+ * @see android.media.tv.interactive.TvInteractiveAppServiceInfo#getSupportedTypes()
* @see android.media.tv.interactive.TvInteractiveAppView#createBiInteractiveApp(Uri, Bundle)
*/
public static final String INTENT_KEY_BI_INTERACTIVE_APP_TYPE = "bi_interactive_app_type";
@@ -543,11 +543,11 @@
}
@Override
- public void onTvInteractiveAppInfoUpdated(TvInteractiveAppInfo iAppInfo) {
+ public void onTvInteractiveAppServiceInfoUpdated(TvInteractiveAppServiceInfo iAppInfo) {
// TODO: add public API updateInteractiveAppInfo()
synchronized (mLock) {
for (TvInteractiveAppCallbackRecord record : mCallbackRecords) {
- record.postTvInteractiveAppInfoUpdated(iAppInfo);
+ record.postTvInteractiveAppServiceInfoUpdated(iAppInfo);
}
}
}
@@ -611,16 +611,17 @@
* This is called when the information about an existing TV Interactive App service has been
* updated.
*
- * <p>Because the system automatically creates a <code>TvInteractiveAppInfo</code> object
- * for each TV Interactive App service based on the information collected from the
+ * <p>Because the system automatically creates a <code>TvInteractiveAppServiceInfo</code>
+ * object for each TV Interactive App service based on the information collected from the
* <code>AndroidManifest.xml</code>, this method is only called back when such information
* has changed dynamically.
*
- * @param iAppInfo The <code>TvInteractiveAppInfo</code> object that contains new
+ * @param iAppInfo The <code>TvInteractiveAppServiceInfo</code> object that contains new
* information.
* @hide
*/
- public void onTvInteractiveAppInfoUpdated(@NonNull TvInteractiveAppInfo iAppInfo) {
+ public void onTvInteractiveAppServiceInfoUpdated(
+ @NonNull TvInteractiveAppServiceInfo iAppInfo) {
}
/**
@@ -634,7 +635,7 @@
*/
public void onTvInteractiveAppServiceStateChanged(
@NonNull String iAppServiceId,
- @TvInteractiveAppInfo.InteractiveAppType int type,
+ @TvInteractiveAppServiceInfo.InteractiveAppType int type,
@ServiceState int state,
@ErrorCode int err) {
}
@@ -680,11 +681,12 @@
});
}
- public void postTvInteractiveAppInfoUpdated(final TvInteractiveAppInfo iAppInfo) {
+ public void postTvInteractiveAppServiceInfoUpdated(
+ final TvInteractiveAppServiceInfo iAppInfo) {
mExecutor.execute(new Runnable() {
@Override
public void run() {
- mCallback.onTvInteractiveAppInfoUpdated(iAppInfo);
+ mCallback.onTvInteractiveAppServiceInfoUpdated(iAppInfo);
}
});
}
@@ -737,11 +739,11 @@
/**
* Returns the complete list of TV Interactive App service on the system.
*
- * @return List of {@link TvInteractiveAppInfo} for each TV Interactive App service that
+ * @return List of {@link TvInteractiveAppServiceInfo} for each TV Interactive App service that
* describes its meta information.
*/
@NonNull
- public List<TvInteractiveAppInfo> getTvInteractiveAppServiceList() {
+ public List<TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList() {
try {
return mService.getTvInteractiveAppServiceList(mUserId);
} catch (RemoteException e) {
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index d22fd83..316fbbab 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -242,7 +242,7 @@
/**
* Prepares TV Interactive App service for the given type.
*/
- public abstract void onPrepare(@TvInteractiveAppInfo.InteractiveAppType int type);
+ public abstract void onPrepare(@TvInteractiveAppServiceInfo.InteractiveAppType int type);
/**
* Called when a request to register an Android application link info record is received.
@@ -277,7 +277,7 @@
@Nullable
public abstract Session onCreateSession(
@NonNull String iAppServiceId,
- @TvInteractiveAppInfo.InteractiveAppType int type);
+ @TvInteractiveAppServiceInfo.InteractiveAppType int type);
/**
* Notifies the system when the state of the interactive app RTE has been changed.
@@ -289,7 +289,7 @@
* {@link TvInteractiveAppManager#SERVICE_STATE_ERROR}.
*/
public final void notifyStateChanged(
- @TvInteractiveAppInfo.InteractiveAppType int type,
+ @TvInteractiveAppServiceInfo.InteractiveAppType int type,
@TvInteractiveAppManager.ServiceState int state,
@TvInteractiveAppManager.ErrorCode int error) {
SomeArgs args = SomeArgs.obtain();
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl
similarity index 94%
rename from media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl
rename to media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl
index 5e15016..49600a0 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl
@@ -16,4 +16,4 @@
package android.media.tv.interactive;
-parcelable TvInteractiveAppInfo;
\ No newline at end of file
+parcelable TvInteractiveAppServiceInfo;
\ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
similarity index 89%
rename from media/java/android/media/tv/interactive/TvInteractiveAppInfo.java
rename to media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
index 6103db0..9c1b242 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
@@ -45,9 +45,9 @@
/**
* This class is used to specify meta information of a TV interactive app.
*/
-public final class TvInteractiveAppInfo implements Parcelable {
+public final class TvInteractiveAppServiceInfo implements Parcelable {
private static final boolean DEBUG = false;
- private static final String TAG = "TvInteractiveAppInfo";
+ private static final String TAG = "TvInteractiveAppServiceInfo";
private static final String XML_START_TAG_NAME = "tv-interactive-app";
@@ -71,7 +71,7 @@
private final String mId;
private int mTypes;
- public TvInteractiveAppInfo(@NonNull Context context, @NonNull ComponentName component) {
+ public TvInteractiveAppServiceInfo(@NonNull Context context, @NonNull ComponentName component) {
if (context == null) {
throw new IllegalArgumentException("context cannot be null.");
}
@@ -94,28 +94,28 @@
mId = id;
mTypes = toTypesFlag(types);
}
- private TvInteractiveAppInfo(ResolveInfo service, String id, int types) {
+ private TvInteractiveAppServiceInfo(ResolveInfo service, String id, int types) {
mService = service;
mId = id;
mTypes = types;
}
- private TvInteractiveAppInfo(@NonNull Parcel in) {
+ private TvInteractiveAppServiceInfo(@NonNull Parcel in) {
mService = ResolveInfo.CREATOR.createFromParcel(in);
mId = in.readString();
mTypes = in.readInt();
}
- public static final @NonNull Creator<TvInteractiveAppInfo> CREATOR =
- new Creator<TvInteractiveAppInfo>() {
+ public static final @NonNull Creator<TvInteractiveAppServiceInfo> CREATOR =
+ new Creator<TvInteractiveAppServiceInfo>() {
@Override
- public TvInteractiveAppInfo createFromParcel(Parcel in) {
- return new TvInteractiveAppInfo(in);
+ public TvInteractiveAppServiceInfo createFromParcel(Parcel in) {
+ return new TvInteractiveAppServiceInfo(in);
}
@Override
- public TvInteractiveAppInfo[] newArray(int size) {
- return new TvInteractiveAppInfo[size];
+ public TvInteractiveAppServiceInfo[] newArray(int size) {
+ return new TvInteractiveAppServiceInfo[size];
}
};
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 773e54f..2120511 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -148,12 +148,14 @@
/**
* Sets the callback to be invoked when an event is dispatched to this TvInteractiveAppView.
*
- * @param callback The callback to receive events. A value of {@code null} removes the existing
- * callback.
+ * @param callback the callback to receive events. MUST NOT be {@code null}.
+ *
+ * @see #clearCallback()
*/
public void setCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull TvInteractiveAppCallback callback) {
+ com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, callback);
synchronized (mCallbackLock) {
mCallbackExecutor = executor;
mCallback = callback;
@@ -162,6 +164,8 @@
/**
* Clears the callback.
+ *
+ * @see #setCallback(Executor, TvInteractiveAppCallback)
*/
public void clearCallback() {
synchronized (mCallbackLock) {
@@ -389,13 +393,13 @@
* Prepares the interactive application.
*
* @param iAppServiceId the interactive app service ID, which can be found in
- * {@link TvInteractiveAppInfo#getId()}.
+ * {@link TvInteractiveAppServiceInfo#getId()}.
*
* @see android.media.tv.interactive.TvInteractiveAppManager#getTvInteractiveAppServiceList()
*/
public void prepareInteractiveApp(
@NonNull String iAppServiceId,
- @TvInteractiveAppInfo.InteractiveAppType int type) {
+ @TvInteractiveAppServiceInfo.InteractiveAppType int type) {
// TODO: document and handle the cases that this method is called multiple times.
if (DEBUG) {
Log.d(TAG, "prepareInteractiveApp");
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 55a1998..67fc6c2 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -82,7 +82,7 @@
<string name="permission_notification">Notifications</string>
<!-- Description of notification permission of COMPUTER profile [CHAR LIMIT=NONE] -->
- <string name="permission_notification_summary">Can read all notifications, including information like contracts, messages, and photos</string>
+ <string name="permission_notification_summary">Can read all notifications, including information like contacts, messages, and photos</string>
<!-- Storage permission will be granted of COMPUTER profile [CHAR LIMIT=30] -->
<string name="permission_storage">Photos and media</string>
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
index 2b6570a..74fe4bd 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
@@ -17,6 +17,7 @@
package android.app.usage;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.content.Context;
import android.net.INetworkStatsService;
import android.net.INetworkStatsSession;
@@ -474,10 +475,11 @@
/**
* Fills the recycled bucket with data of the next bin in the enumeration.
- * @param bucketOut Bucket to be filled with data.
+ * @param bucketOut Bucket to be filled with data. If null, the method does
+ * nothing and returning false.
* @return true if successfully filled the bucket, false otherwise.
*/
- public boolean getNextBucket(Bucket bucketOut) {
+ public boolean getNextBucket(@Nullable Bucket bucketOut) {
if (mSummary != null) {
return getNextSummaryBucket(bucketOut);
} else {
@@ -651,7 +653,7 @@
* @param bucketOut Next item will be set here.
* @return true if a next item could be set.
*/
- private boolean getNextSummaryBucket(Bucket bucketOut) {
+ private boolean getNextSummaryBucket(@Nullable Bucket bucketOut) {
if (bucketOut != null && mEnumerationIndex < mSummary.size()) {
mRecycledSummaryEntry = mSummary.getValues(mEnumerationIndex++, mRecycledSummaryEntry);
fillBucketFromSummaryEntry(bucketOut);
@@ -678,7 +680,7 @@
* @param bucketOut Next item will be set here.
* @return true if a next item could be set.
*/
- private boolean getNextHistoryBucket(Bucket bucketOut) {
+ private boolean getNextHistoryBucket(@Nullable Bucket bucketOut) {
if (bucketOut != null && mHistory != null) {
if (mEnumerationIndex < mHistory.size()) {
mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++,
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
index ca080ce..f41475b 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -290,7 +290,7 @@
* statistics collection.
*/
@WorkerThread
- public Bucket querySummaryForDevice(int networkType, String subscriberId,
+ public Bucket querySummaryForDevice(int networkType, @Nullable String subscriberId,
long startTime, long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
@@ -335,8 +335,8 @@
* statistics collection.
*/
@WorkerThread
- public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
- long endTime) throws SecurityException, RemoteException {
+ public Bucket querySummaryForUser(int networkType, @Nullable String subscriberId,
+ long startTime, long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
template = createTemplate(networkType, subscriberId);
@@ -384,7 +384,7 @@
* statistics collection.
*/
@WorkerThread
- public NetworkStats querySummary(int networkType, String subscriberId, long startTime,
+ public NetworkStats querySummary(int networkType, @Nullable String subscriberId, long startTime,
long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
@@ -508,15 +508,17 @@
*
* @see #queryDetailsForUidTagState(int, String, long, long, int, int, int)
*/
+ @NonNull
@WorkerThread
- public NetworkStats queryDetailsForUid(int networkType, String subscriberId,
+ public NetworkStats queryDetailsForUid(int networkType, @Nullable String subscriberId,
long startTime, long endTime, int uid) throws SecurityException {
return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL);
}
/** @hide */
- public NetworkStats queryDetailsForUid(NetworkTemplate template,
+ @NonNull
+ public NetworkStats queryDetailsForUid(@NonNull NetworkTemplate template,
long startTime, long endTime, int uid) throws SecurityException {
return queryDetailsForUidTagState(template, startTime, endTime, uid,
NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL);
@@ -524,23 +526,59 @@
/**
* Query network usage statistics details for a given uid and tag.
+ *
+ * This may take a long time, and apps should avoid calling this on their main thread.
+ * Only usable for uids belonging to calling user. Result is not aggregated over time.
+ * This means buckets' start and end timestamps are going to be between 'startTime' and
+ * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag
+ * the same as the 'tag' parameter, and the state the same as the 'state' parameter.
+ * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
+ * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and
+ * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
+ * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
+ * interpolate across partial buckets. Since bucket length is in the order of hours, this
+ * method cannot be used to measure data usage on a fine grained time scale.
* This may take a long time, and apps should avoid calling this on their main thread.
*
- * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int)
+ * @param networkType As defined in {@link ConnectivityManager}, e.g.
+ * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
+ * etc.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * <p>Starting with API level 29, the {@code subscriberId} is guarded by
+ * additional restrictions. Calling apps that do not meet the new
+ * requirements to access the {@code subscriberId} can provide a {@code
+ * null} value when querying for the mobile network type to receive usage
+ * for all mobile networks. For additional details see {@link
+ * TelephonyManager#getSubscriberId()}.
+ * <p>Starting with API level 31, calling apps can provide a
+ * {@code subscriberId} with wifi network type to receive usage for
+ * wifi networks which is under the given subscription if applicable.
+ * Otherwise, pass {@code null} when querying all wifi networks.
+ * @param startTime Start of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param uid UID of app
+ * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data
+ * across all the tags.
+ * @return Statistics which is described above.
+ * @throws SecurityException if permissions are insufficient to read network statistics.
*/
+ @NonNull
@WorkerThread
- public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId,
+ public NetworkStats queryDetailsForUidTag(int networkType, @Nullable String subscriberId,
long startTime, long endTime, int uid, int tag) throws SecurityException {
return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
tag, NetworkStats.Bucket.STATE_ALL);
}
/**
- * Query network usage statistics details for a given uid, tag, and state. Only usable for uids
- * belonging to calling user. Result is not aggregated over time. This means buckets' start and
- * end timestamps are going to be between 'startTime' and 'endTime' parameters. The uid is going
- * to be the same as the 'uid' parameter, the tag the same as the 'tag' parameter, and the state
- * the same as the 'state' parameter.
+ * Query network usage statistics details for a given uid, tag, and state.
+ *
+ * Only usable for uids belonging to calling user. Result is not aggregated over time.
+ * This means buckets' start and end timestamps are going to be between 'startTime' and
+ * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag
+ * the same as the 'tag' parameter, and the state the same as the 'state' parameter.
* defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
* metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and
* roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
@@ -572,11 +610,12 @@
* across all the tags.
* @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate
* traffic from all states.
- * @return Statistics object or null if an error happened during statistics collection.
+ * @return Statistics which is described above.
* @throws SecurityException if permissions are insufficient to read network statistics.
*/
+ @NonNull
@WorkerThread
- public NetworkStats queryDetailsForUidTagState(int networkType, String subscriberId,
+ public NetworkStats queryDetailsForUidTagState(int networkType, @Nullable String subscriberId,
long startTime, long endTime, int uid, int tag, int state) throws SecurityException {
NetworkTemplate template;
template = createTemplate(networkType, subscriberId);
@@ -669,7 +708,7 @@
* statistics collection.
*/
@WorkerThread
- public NetworkStats queryDetails(int networkType, String subscriberId, long startTime,
+ public NetworkStats queryDetails(int networkType, @Nullable String subscriberId, long startTime,
long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
@@ -698,7 +737,7 @@
*
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
@@ -724,7 +763,7 @@
*
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
@@ -785,10 +824,28 @@
/**
* Registers to receive notifications about data usage on specified networks.
*
- * @see #registerUsageCallback(int, String, long, UsageCallback, Handler)
+ * <p>The callbacks will continue to be called as long as the process is live or
+ * {@link #unregisterUsageCallback} is called.
+ *
+ * @param networkType Type of network to monitor. Either
+ {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * <p>Starting with API level 29, the {@code subscriberId} is guarded by
+ * additional restrictions. Calling apps that do not meet the new
+ * requirements to access the {@code subscriberId} can provide a {@code
+ * null} value when registering for the mobile network type to receive
+ * notifications for all mobile networks. For additional details see {@link
+ * TelephonyManager#getSubscriberId()}.
+ * <p>Starting with API level 31, calling apps can provide a
+ * {@code subscriberId} with wifi network type to receive usage for
+ * wifi networks which is under the given subscription if applicable.
+ * Otherwise, pass {@code null} when querying all wifi networks.
+ * @param thresholdBytes Threshold in bytes to be notified on.
+ * @param callback The {@link UsageCallback} that the system will call when data usage
+ * has exceeded the specified threshold.
*/
- public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
- UsageCallback callback) {
+ public void registerUsageCallback(int networkType, @Nullable String subscriberId,
+ long thresholdBytes, @NonNull UsageCallback callback) {
registerUsageCallback(networkType, subscriberId, thresholdBytes, callback,
null /* handler */);
}
@@ -818,8 +875,8 @@
* @param handler to dispatch callback events through, otherwise if {@code null} it uses
* the calling thread.
*/
- public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
- UsageCallback callback, @Nullable Handler handler) {
+ public void registerUsageCallback(int networkType, @Nullable String subscriberId,
+ long thresholdBytes, @NonNull UsageCallback callback, @Nullable Handler handler) {
NetworkTemplate template = createTemplate(networkType, subscriberId);
if (DBG) {
Log.d(TAG, "registerUsageCallback called with: {"
@@ -839,7 +896,7 @@
*
* @param callback The {@link UsageCallback} used when registering.
*/
- public void unregisterUsageCallback(UsageCallback callback) {
+ public void unregisterUsageCallback(@NonNull UsageCallback callback) {
if (callback == null || callback.request == null
|| callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) {
throw new IllegalArgumentException("Invalid UsageCallback");
@@ -880,7 +937,7 @@
/**
* Called when data usage has reached the given threshold.
*/
- public abstract void onThresholdReached(int networkType, String subscriberId);
+ public abstract void onThresholdReached(int networkType, @Nullable String subscriberId);
/**
* @hide used for internal bookkeeping
@@ -924,7 +981,7 @@
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STATS_PROVIDER,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
- @NonNull public void registerNetworkStatsProvider(
+ public void registerNetworkStatsProvider(
@NonNull String tag,
@NonNull NetworkStatsProvider provider) {
try {
@@ -950,7 +1007,7 @@
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STATS_PROVIDER,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
- @NonNull public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) {
+ public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) {
try {
provider.getProviderCallbackBinderOrThrow().unregister();
} catch (RemoteException e) {
@@ -958,7 +1015,7 @@
}
}
- private static NetworkTemplate createTemplate(int networkType, String subscriberId) {
+ private static NetworkTemplate createTemplate(int networkType, @Nullable String subscriberId) {
final NetworkTemplate template;
switch (networkType) {
case ConnectivityManager.TYPE_MOBILE:
@@ -1061,9 +1118,9 @@
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
- public void setUidForeground(int uid, boolean uidForeground) {
+ public void noteUidForeground(int uid, boolean uidForeground) {
try {
- mService.setUidForeground(uid, uidForeground);
+ mService.noteUidForeground(uid, uidForeground);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
index 43f4c40f..1691942 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
@@ -33,17 +33,20 @@
*/
@SystemApi
public final class EthernetNetworkUpdateRequest implements Parcelable {
- @NonNull
+ @Nullable
private final IpConfiguration mIpConfig;
@Nullable
private final NetworkCapabilities mNetworkCapabilities;
/**
- * @return the new {@link IpConfiguration}.
+ * Setting the {@link IpConfiguration} is optional in {@link EthernetNetworkUpdateRequest}.
+ * When set to null, the existing IpConfiguration is not updated.
+ *
+ * @return the new {@link IpConfiguration} or null.
*/
- @NonNull
+ @Nullable
public IpConfiguration getIpConfiguration() {
- return new IpConfiguration(mIpConfig);
+ return mIpConfig == null ? null : new IpConfiguration(mIpConfig);
}
/**
@@ -57,9 +60,8 @@
return mNetworkCapabilities == null ? null : new NetworkCapabilities(mNetworkCapabilities);
}
- private EthernetNetworkUpdateRequest(@NonNull final IpConfiguration ipConfig,
+ private EthernetNetworkUpdateRequest(@Nullable final IpConfiguration ipConfig,
@Nullable final NetworkCapabilities networkCapabilities) {
- Objects.requireNonNull(ipConfig);
mIpConfig = ipConfig;
mNetworkCapabilities = networkCapabilities;
}
@@ -90,7 +92,8 @@
*/
public Builder(@NonNull final EthernetNetworkUpdateRequest request) {
Objects.requireNonNull(request);
- mBuilderIpConfig = new IpConfiguration(request.mIpConfig);
+ mBuilderIpConfig = null == request.mIpConfig
+ ? null : new IpConfiguration(request.mIpConfig);
mBuilderNetworkCapabilities = null == request.mNetworkCapabilities
? null : new NetworkCapabilities(request.mNetworkCapabilities);
}
@@ -101,8 +104,8 @@
* @return The builder to facilitate chaining.
*/
@NonNull
- public Builder setIpConfiguration(@NonNull final IpConfiguration ipConfig) {
- mBuilderIpConfig = new IpConfiguration(ipConfig);
+ public Builder setIpConfiguration(@Nullable final IpConfiguration ipConfig) {
+ mBuilderIpConfig = ipConfig == null ? null : new IpConfiguration(ipConfig);
return this;
}
@@ -119,9 +122,16 @@
/**
* Build {@link EthernetNetworkUpdateRequest} return the current update request.
+ *
+ * @throws IllegalStateException when both mBuilderNetworkCapabilities and mBuilderIpConfig
+ * are null.
*/
@NonNull
public EthernetNetworkUpdateRequest build() {
+ if (mBuilderIpConfig == null && mBuilderNetworkCapabilities == null) {
+ throw new IllegalStateException(
+ "Cannot construct an empty EthernetNetworkUpdateRequest");
+ }
return new EthernetNetworkUpdateRequest(mBuilderIpConfig, mBuilderNetworkCapabilities);
}
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl
index efe626d..c86f7fd 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl
@@ -91,7 +91,7 @@
in INetworkStatsProvider provider);
/** Mark given UID as being in foreground for stats purposes. */
- void setUidForeground(int uid, boolean uidForeground);
+ void noteUidForeground(int uid, boolean uidForeground);
/** Advise persistence threshold; may be overridden internally. */
void advisePersistThreshold(long thresholdBytes);
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
index 06f2a62..bcfeab9 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
@@ -16,6 +16,8 @@
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
import android.annotation.IntDef;
@@ -124,7 +126,6 @@
public @Nullable static final String[] INTERFACES_ALL = null;
/** {@link #tag} value for total data across all tags. */
- // TODO: Rename TAG_NONE to TAG_ALL.
public static final int TAG_NONE = 0;
/** {@link #metered} value to account for all metered states. */
@@ -390,77 +391,102 @@
/**
* @return the uid of this entry.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public int getUid() {
return uid;
}
/**
* @return the set state of this entry.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
@State public int getSet() {
return set;
}
/**
* @return the tag value of this entry.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public int getTag() {
return tag;
}
/**
* @return the metered state.
+ * @hide
*/
- @Meteredness public int getMetered() {
+ @Meteredness
+ @SystemApi(client = MODULE_LIBRARIES)
+ public int getMetered() {
return metered;
}
/**
* @return the roaming state.
+ * @hide
*/
- @Roaming public int getRoaming() {
+ @Roaming
+ @SystemApi(client = MODULE_LIBRARIES)
+ public int getRoaming() {
return roaming;
}
/**
* @return the default network state.
+ * @hide
*/
- @DefaultNetwork public int getDefaultNetwork() {
+ @DefaultNetwork
+ @SystemApi(client = MODULE_LIBRARIES)
+ public int getDefaultNetwork() {
return defaultNetwork;
}
/**
* @return the number of received bytes.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getRxBytes() {
return rxBytes;
}
/**
* @return the number of received packets.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getRxPackets() {
return rxPackets;
}
/**
* @return the number of transmitted bytes.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getTxBytes() {
return txBytes;
}
/**
* @return the number of transmitted packets.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getTxPackets() {
return txPackets;
}
/**
* @return the count of network operations performed for this entry.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getOperations() {
return operations;
}
@@ -682,7 +708,7 @@
* The remove() method is not implemented and will throw UnsupportedOperationException.
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
@NonNull public Iterator<Entry> iterator() {
return new Iterator<Entry>() {
int mIndex = 0;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
index bc836d8..dc4ac55 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
@@ -205,7 +205,7 @@
* server context.
* @hide
*/
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SystemApi(client = MODULE_LIBRARIES)
@SuppressLint("VisiblySynchronized")
public static synchronized void init(@NonNull final Context context) {
if (sStatsService != null) {
@@ -376,7 +376,7 @@
*
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
public static void setThreadStatsTagDownload() {
setThreadStatsTag(TAG_SYSTEM_DOWNLOAD);
}
@@ -468,7 +468,7 @@
*
* @see #setThreadStatsTag(int)
*/
- public static void tagSocket(Socket socket) throws SocketException {
+ public static void tagSocket(@NonNull Socket socket) throws SocketException {
SocketTagger.get().tag(socket);
}
@@ -483,7 +483,7 @@
* calling {@code untagSocket()} before sending the socket to another
* process.
*/
- public static void untagSocket(Socket socket) throws SocketException {
+ public static void untagSocket(@NonNull Socket socket) throws SocketException {
SocketTagger.get().untag(socket);
}
@@ -496,14 +496,14 @@
*
* @see #setThreadStatsTag(int)
*/
- public static void tagDatagramSocket(DatagramSocket socket) throws SocketException {
+ public static void tagDatagramSocket(@NonNull DatagramSocket socket) throws SocketException {
SocketTagger.get().tag(socket);
}
/**
* Remove any statistics parameters from the given {@link DatagramSocket}.
*/
- public static void untagDatagramSocket(DatagramSocket socket) throws SocketException {
+ public static void untagDatagramSocket(@NonNull DatagramSocket socket) throws SocketException {
SocketTagger.get().untag(socket);
}
@@ -516,7 +516,7 @@
*
* @see #setThreadStatsTag(int)
*/
- public static void tagFileDescriptor(FileDescriptor fd) throws IOException {
+ public static void tagFileDescriptor(@NonNull FileDescriptor fd) throws IOException {
SocketTagger.get().tag(fd);
}
@@ -524,7 +524,7 @@
* Remove any statistics parameters from the given {@link FileDescriptor}
* socket.
*/
- public static void untagFileDescriptor(FileDescriptor fd) throws IOException {
+ public static void untagFileDescriptor(@NonNull FileDescriptor fd) throws IOException {
SocketTagger.get().untag(fd);
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
index 7eaa01e..01ff02d 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
@@ -26,6 +26,7 @@
oneway interface INetworkStatsProviderCallback {
void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats);
void notifyAlertReached();
- void notifyWarningOrLimitReached();
+ void notifyWarningReached();
+ void notifyLimitReached();
void unregister();
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java
index 23fc069..d37a53d 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java
@@ -152,19 +152,19 @@
try {
// Reuse the code path to notify warning reached with limit reached
// since framework handles them in the same way.
- getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
+ getProviderCallbackBinderOrThrow().notifyWarningReached();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
/**
- * Notify system that the quota set by {@link #onSetLimit} or limit set by
+ * Notify system that the limit set by {@link #onSetLimit} or limit set by
* {@link #onSetWarningAndLimit} has been reached.
*/
public void notifyLimitReached() {
try {
- getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
+ getProviderCallbackBinderOrThrow().notifyLimitReached();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
index 1d22908..e3794e4 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
@@ -1194,7 +1194,7 @@
}
@VisibleForTesting
- public void setUidForeground(int uid, boolean uidForeground) {
+ public void noteUidForeground(int uid, boolean uidForeground) {
PermissionUtils.enforceNetworkStackPermission(mContext);
synchronized (mStatsLock) {
final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT;
@@ -2393,10 +2393,17 @@
}
@Override
- public void notifyWarningOrLimitReached() {
- Log.d(TAG, mTag + ": notifyWarningOrLimitReached");
+ public void notifyWarningReached() {
+ Log.d(TAG, mTag + ": notifyWarningReached");
BinderUtils.withCleanCallingIdentity(() ->
- mNetworkPolicyManager.notifyStatsProviderWarningOrLimitReached());
+ mNetworkPolicyManager.notifyStatsProviderWarningReached());
+ }
+
+ @Override
+ public void notifyLimitReached() {
+ Log.d(TAG, mTag + ": notifyLimitReached");
+ BinderUtils.withCleanCallingIdentity(() ->
+ mNetworkPolicyManager.notifyStatsProviderLimitReached());
}
@Override
diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml
new file mode 100644
index 0000000..221d2db
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:alpha="?android:attr/disabledAlpha"
+ android:color="@color/settingslib_text_color_primary_device_default"/>
+ <item android:color="@color/settingslib_text_color_primary_device_default"/>
+</selector>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 9d39911..cba1a9c 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -17,7 +17,7 @@
<resources>
<style name="TextAppearance.PreferenceTitle.SettingsLib"
parent="@android:style/TextAppearance.Material.Subhead">
- <item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
+ <item name="android:textColor">@color/settingslib_text_color_primary</item>
<item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textSize">20sp</item>
</style>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 579e3d7..7439428 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1582,4 +1582,11 @@
<string name="keyboard_layout_dialog_title">Choose keyboard layout</string>
<!-- Label of the default keyboard layout. [CHAR LIMIT=35] -->
<string name="keyboard_layout_default_label">Default</string>
+
+ <!-- Special access > Title for managing turn screen on settings. [CHAR LIMIT=50] -->
+ <string name="turn_screen_on_title">Turn screen on</string>
+ <!-- Label for a setting which controls whether an app can turn the screen on [CHAR LIMIT=45] -->
+ <string name="allow_turn_screen_on">Allow turning the screen on</string>
+ <!-- Description for a setting which controls whether an app can turn the screen on [CHAR LIMIT=NONE] -->
+ <string name="allow_turn_screen_on_description">Allow an app to turn the screen on. If granted, the app may turn on the screen at any time without your explicit intent.</string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 3d91c5a..2a28891 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -753,7 +753,10 @@
ParcelUuid[] uuids = mDevice.getUuids();
if (uuids == null) return false;
- ParcelUuid[] localUuids = mLocalAdapter.getUuids();
+ List<ParcelUuid> uuidsList = mLocalAdapter.getUuidsList();
+ ParcelUuid[] localUuids = new ParcelUuid[uuidsList.size()];
+ uuidsList.toArray(localUuids);
+
if (localUuids == null) return false;
/*
@@ -1117,7 +1120,8 @@
final boolean isOnCall = Utils.isAudioModeOngoingCall(mContext);
if ((mIsActiveDeviceHearingAid)
|| (mIsActiveDeviceHeadset && isOnCall)
- || (mIsActiveDeviceA2dp && !isOnCall)) {
+ || (mIsActiveDeviceA2dp && !isOnCall)
+ || mIsActiveDeviceLeAudio) {
if (isTwsBatteryAvailable(leftBattery, rightBattery) && !shortSummary) {
stringRes = R.string.bluetooth_active_battery_level_untethered;
} else if (batteryLevelPercentageString != null && !shortSummary) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
index e203cba..19df1e9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
@@ -246,6 +246,13 @@
return R.drawable.ic_bt_le_audio;
}
+ public int getAudioLocation(BluetoothDevice device) {
+ if (mService == null || device == null) {
+ return BluetoothLeAudio.AUDIO_LOCATION_INVALID;
+ }
+ return mService.getAudioLocation(device);
+ }
+
@RequiresApi(Build.VERSION_CODES.S)
protected void finalize() {
if (DEBUG) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
index e7a6b32..31cc6a4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -126,7 +126,10 @@
}
public ParcelUuid[] getUuids() {
- return mAdapter.getUuids();
+ List<ParcelUuid> uuidsList = mAdapter.getUuidsList();
+ ParcelUuid[] uuidsArray = new ParcelUuid[uuidsList.size()];
+ uuidsList.toArray(uuidsArray);
+ return uuidsArray;
}
public boolean isDiscovering() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
index 0cb2c0b..63a9f0c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
@@ -78,6 +78,11 @@
static final int REQUEST_CODE_TAKE_PHOTO = 1002;
static final int REQUEST_CODE_CROP_PHOTO = 1003;
+ /**
+ * Delay to allow the photo picker exit animation to complete before the crop activity opens.
+ */
+ private static final long DELAY_BEFORE_CROP_MILLIS = 150;
+
private static final String IMAGES_DIR = "multi_user";
private static final String PRE_CROP_PICTURE_FILE_NAME = "PreCropEditUserPhoto.jpg";
private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg";
@@ -131,13 +136,15 @@
mAvatarUi.returnUriResult(pictureUri);
return true;
case REQUEST_CODE_TAKE_PHOTO:
- case REQUEST_CODE_CHOOSE_PHOTO:
if (mTakePictureUri.equals(pictureUri)) {
cropPhoto(pictureUri);
} else {
- copyAndCropPhoto(pictureUri);
+ copyAndCropPhoto(pictureUri, false);
}
return true;
+ case REQUEST_CODE_CHOOSE_PHOTO:
+ copyAndCropPhoto(pictureUri, true);
+ return true;
}
return false;
}
@@ -154,7 +161,7 @@
mAvatarUi.startActivityForResult(intent, REQUEST_CODE_CHOOSE_PHOTO);
}
- private void copyAndCropPhoto(final Uri pictureUri) {
+ private void copyAndCropPhoto(final Uri pictureUri, boolean delayBeforeCrop) {
try {
ThreadUtils.postOnBackgroundThread(() -> {
final ContentResolver cr = mContextInjector.getContentResolver();
@@ -165,11 +172,17 @@
Log.w(TAG, "Failed to copy photo", e);
return;
}
- ThreadUtils.postOnMainThread(() -> {
+ Runnable cropRunnable = () -> {
if (!mAvatarUi.isFinishing()) {
cropPhoto(mPreCropPictureUri);
}
- });
+ };
+ if (delayBeforeCrop) {
+ ThreadUtils.postOnMainThreadDelayed(cropRunnable, DELAY_BEFORE_CROP_MILLIS);
+ } else {
+ ThreadUtils.postOnMainThread(cropRunnable);
+ }
+
}).get();
} catch (InterruptedException | ExecutionException e) {
Log.e(TAG, "Error performing copy-and-crop", e);
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
index 69f1c17..2c1d5da 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
@@ -84,6 +84,13 @@
getUiThreadHandler().post(runnable);
}
+ /**
+ * Posts the runnable on the main thread with a delay.
+ */
+ public static void postOnMainThreadDelayed(Runnable runnable, long delayMillis) {
+ getUiThreadHandler().postDelayed(runnable, delayMillis);
+ }
+
private static synchronized ExecutorService getThreadExecutor() {
if (sThreadExecutor == null) {
sThreadExecutor = Executors.newFixedThreadPool(
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 4b45cc3..e24b2d6 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -314,11 +314,6 @@
<!-- To change system captions state -->
<uses-permission android:name="android.permission.SET_SYSTEM_AUDIO_CAPTION" />
- <!-- Compat framework -->
- <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
- <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
- <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
-
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
diff --git a/packages/SystemUI/res/drawable/ic_circular_unchecked.xml b/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
index 9b43cf6..779ab81 100644
--- a/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
+++ b/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
- android:fillColor="@color/media_dialog_inactive_item_main_content"
+ android:fillColor="@color/media_dialog_item_main_content"
android:pathData="M12,22q-2.075,0 -3.9,-0.788 -1.825,-0.787 -3.175,-2.137 -1.35,-1.35 -2.137,-3.175Q2,14.075 2,12t0.788,-3.9q0.787,-1.825 2.137,-3.175 1.35,-1.35 3.175,-2.137Q9.925,2 12,2t3.9,0.788q1.825,0.787 3.175,2.137 1.35,1.35 2.137,3.175Q22,9.925 22,12t-0.788,3.9q-0.787,1.825 -2.137,3.175 -1.35,1.35 -3.175,2.137Q14.075,22 12,22zM12,12zM12,20q3.325,0 5.663,-2.337Q20,15.325 20,12t-2.337,-5.662Q15.325,4 12,4T6.338,6.338Q4,8.675 4,12q0,3.325 2.338,5.663Q8.675,20 12,20z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/media_output_status_check.xml b/packages/SystemUI/res/drawable/media_output_status_check.xml
index 1b750f8..5fbc42b 100644
--- a/packages/SystemUI/res/drawable/media_output_status_check.xml
+++ b/packages/SystemUI/res/drawable/media_output_status_check.xml
@@ -21,6 +21,6 @@
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
- android:fillColor="@color/media_dialog_item_status"
+ android:fillColor="@color/media_dialog_item_main_content"
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/media_output_status_failed.xml b/packages/SystemUI/res/drawable/media_output_status_failed.xml
index 05c6358..0599e23 100644
--- a/packages/SystemUI/res/drawable/media_output_status_failed.xml
+++ b/packages/SystemUI/res/drawable/media_output_status_failed.xml
@@ -21,6 +21,6 @@
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
- android:fillColor="@color/media_dialog_inactive_item_main_content"
+ android:fillColor="@color/media_dialog_item_main_content"
android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index eeb37c7..20747fa 100644
--- a/packages/SystemUI/res/layout/media_output_list_item.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item.xml
@@ -83,7 +83,7 @@
android:ellipsize="end"
android:maxLines="1"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- android:textColor="@color/media_dialog_inactive_item_main_content"
+ android:textColor="@color/media_dialog_item_main_content"
android:textSize="16sp"/>
<TextView
android:id="@+id/subtitle"
@@ -91,7 +91,7 @@
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
- android:textColor="@color/media_dialog_inactive_item_main_content"
+ android:textColor="@color/media_dialog_item_main_content"
android:textSize="14sp"
android:fontFamily="@*android:string/config_bodyFontFamily"
android:visibility="gone"/>
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
index ad2bc79..5aa6080 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
@@ -37,7 +37,5 @@
android:layout_gravity="center"
android:minWidth="@dimen/ongoing_appops_chip_min_width"
android:maxWidth="@dimen/ongoing_appops_chip_max_width"
- android:clipChildren="false"
- android:clipToPadding="false"
/>
</com.android.systemui.privacy.OngoingPrivacyChip>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 4b96d5d..3a638b1 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -67,10 +67,12 @@
<!-- media output dialog-->
<color name="media_dialog_background">@color/material_dynamic_neutral10</color>
- <color name="media_dialog_active_item_main_content">@color/material_dynamic_neutral10</color>
- <color name="media_dialog_inactive_item_main_content">@color/material_dynamic_neutral10</color>
- <color name="media_dialog_item_status">@color/material_dynamic_neutral10</color>
- <color name="media_dialog_item_background">@color/material_dynamic_secondary95</color>
+ <color name="media_dialog_item_main_content">@color/material_dynamic_primary90</color>
+ <color name="media_dialog_item_background">@color/material_dynamic_neutral_variant20</color>
+ <color name="media_dialog_connected_item_background">@color/material_dynamic_secondary20</color>
+ <color name="media_dialog_seekbar_progress">@color/material_dynamic_secondary40</color>
+ <color name="media_dialog_button_background">@color/material_dynamic_primary70</color>
+ <color name="media_dialog_solid_button_text">@color/material_dynamic_secondary20</color>
<!-- Biometric dialog colors -->
<color name="biometric_dialog_gray">#ffcccccc</color>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index c56ba7b..740697b 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -37,6 +37,7 @@
<dimen name="controls_task_view_right_margin">8dp</dimen>
<dimen name="split_shade_header_height">42dp</dimen>
+ <dimen name="status_bar_header_height_keyguard">42dp</dimen>
<!-- Distance that the full shade transition takes in order to complete by tapping on a button
like "expand". -->
@@ -53,6 +54,14 @@
the shade (in alpha) -->
<dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen>
+ <!-- The notifications scrim transition should start when the other scrims' transition is at
+ 95%. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_delay">76dp</dimen>
+
+ <!-- The notifications scrim transition duration is 66.6% of the duration of the other scrims'
+ transition. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_distance">53.28dp</dimen>
+
<!-- Distance that the full shade transition takes in order for the keyguard content on
NotificationPanelViewController to fully fade (e.g. Clock & Smartspace) -->
<dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">80dp</dimen>
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
index f267088..bdd7049 100644
--- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -24,6 +24,7 @@
<dimen name="keyguard_split_shade_top_margin">72dp</dimen>
<dimen name="split_shade_header_height">56dp</dimen>
+ <dimen name="status_bar_header_height_keyguard">56dp</dimen>
<dimen name="qs_media_session_height_expanded">184dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 1edaaad..49fc848 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -176,10 +176,12 @@
<!-- media output dialog-->
<color name="media_dialog_background" android:lstar="98">@color/material_dynamic_neutral90</color>
- <color name="media_dialog_active_item_main_content">@color/material_dynamic_primary10</color>
- <color name="media_dialog_inactive_item_main_content">@color/material_dynamic_primary40</color>
- <color name="media_dialog_item_status">@color/material_dynamic_primary10</color>
+ <color name="media_dialog_item_main_content">@color/material_dynamic_primary20</color>
<color name="media_dialog_item_background">@color/material_dynamic_secondary95</color>
+ <color name="media_dialog_connected_item_background">@color/material_dynamic_primary90</color>
+ <color name="media_dialog_seekbar_progress">@color/material_dynamic_secondary40</color>
+ <color name="media_dialog_button_background">@color/material_dynamic_primary40</color>
+ <color name="media_dialog_solid_button_text">@color/material_dynamic_neutral95</color>
<!-- controls -->
<color name="control_primary_text">#E6FFFFFF</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ffae601..6871310 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -941,6 +941,9 @@
<!-- Three privacy items. This value must not be exceeded -->
<dimen name="ongoing_appops_chip_max_width">76dp</dimen>
<dimen name="ongoing_appops_dot_diameter">6dp</dimen>
+ <dimen name="ongoing_appops_chip_min_animation_width">10dp</dimen>
+ <dimen name="ongoing_appops_chip_animation_in_status_bar_translation_x">15dp</dimen>
+ <dimen name="ongoing_appops_chip_animation_out_status_bar_translation_x">7dp</dimen>
<!-- Total minimum padding to enforce to ensure that the dot can always show -->
<dimen name="ongoing_appops_dot_min_padding">20dp</dimen>
@@ -1138,6 +1141,12 @@
the shade (in alpha) -->
<dimen name="lockscreen_shade_scrim_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+ <!-- Distance that it takes in order for the notifications scrim fade in to start. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_delay">0dp</dimen>
+
+ <!-- Distance that it takes for the notifications scrim to fully fade if after it started. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_distance">@dimen/lockscreen_shade_scrim_transition_distance</dimen>
+
<!-- Distance that the full shade transition takes in order for the keyguard content on
NotificationPanelViewController to fully fade (e.g. Clock & Smartspace) -->
<dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 3ae21e0..f5c1382 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -486,7 +486,7 @@
<style name="MediaOutputItemInactiveTitle">
<item name="android:textSize">16sp</item>
- <item name="android:textColor">@color/media_dialog_inactive_item_main_content</item>
+ <item name="android:textColor">@color/media_dialog_item_main_content</item>
</style>
<style name="TunerSettings" parent="@android:style/Theme.DeviceDefault.Settings">
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 7e1a026..807ff21 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -254,8 +254,8 @@
mMirrorViewGeometryVsyncCallback =
l -> {
- if (isWindowVisible() && mMirrorSurface != null) {
- calculateSourceBounds(mMagnificationFrame, mScale);
+ if (isWindowVisible() && mMirrorSurface != null && calculateSourceBounds(
+ mMagnificationFrame, mScale)) {
// The final destination for the magnification surface should be at 0,0
// since the ViewRootImpl's position will change
mTmpRect.set(0, 0, mMagnificationFrame.width(),
@@ -350,6 +350,7 @@
mMirrorWindowControl.destroyControl();
}
mMirrorViewBounds.setEmpty();
+ mSourceBounds.setEmpty();
updateSystemUIStateIfNeeded();
mContext.unregisterComponentCallbacks(this);
}
@@ -728,8 +729,12 @@
/**
* Calculates the desired source bounds. This will be the area under from the center of the
* displayFrame, factoring in scale.
+ *
+ * @return {@code true} if the source bounds is changed.
*/
- private void calculateSourceBounds(Rect displayFrame, float scale) {
+ private boolean calculateSourceBounds(Rect displayFrame, float scale) {
+ final Rect oldSourceBounds = mTmpRect;
+ oldSourceBounds.set(mSourceBounds);
int halfWidth = displayFrame.width() / 2;
int halfHeight = displayFrame.height() / 2;
int left = displayFrame.left + (halfWidth - (int) (halfWidth / scale));
@@ -757,6 +762,7 @@
mSourceBounds.offsetTo(mSourceBounds.left,
mWindowBounds.height() - mSourceBounds.height());
}
+ return !mSourceBounds.equals(oldSourceBounds);
}
private void calculateMagnificationFrameBoundary() {
@@ -1079,7 +1085,7 @@
pw.println(" mMagnificationFrame:"
+ (isWindowVisible() ? mMagnificationFrame : "empty"));
pw.println(" mSourceBounds:"
- + (isWindowVisible() ? mSourceBounds : "empty"));
+ + (mSourceBounds.isEmpty() ? "empty" : mSourceBounds));
pw.println(" mSystemGestureTop:" + mSystemGestureTop);
pw.println(" mMagnificationFrameOffsetX:" + mMagnificationFrameOffsetX);
pw.println(" mMagnificationFrameOffsetY:" + mMagnificationFrameOffsetY);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 64c2d2e..c100a07 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -726,8 +726,8 @@
boolean isCameraPrivacyEnabled = false;
if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE
- && mSensorPrivacyManager.isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA,
- mCurrentDialogArgs.argi1 /* userId */)) {
+ && mSensorPrivacyManager.isSensorPrivacyEnabled(
+ SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE, SensorPrivacyManager.Sensors.CAMERA)) {
isCameraPrivacyEnabled = true;
}
// TODO(b/141025588): Create separate methods for handling hard and soft errors.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index a27b9cd..b811c51 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -116,7 +116,7 @@
}
fun showRipple(biometricSourceType: BiometricSourceType?) {
- if (!keyguardUpdateMonitor.isKeyguardVisible ||
+ if (!(keyguardUpdateMonitor.isKeyguardVisible || keyguardUpdateMonitor.isDreaming) ||
keyguardUpdateMonitor.userNeedsStrongAuth()) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 61cfe92..2db3de1 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -145,7 +145,7 @@
/***************************************/
// 900 - media
public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, true);
- public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, false);
+ public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, true);
public static final BooleanFlag MEDIA_SESSION_LAYOUT = new BooleanFlag(902, true);
public static final BooleanFlag MEDIA_NEARBY_DEVICES = new BooleanFlag(903, true);
public static final BooleanFlag MEDIA_MUTE_AWAIT = new BooleanFlag(904, true);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 736e2e0..acad30b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -20,6 +20,7 @@
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_UNLOCK_ANIMATION;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -123,11 +124,11 @@
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -1557,6 +1558,7 @@
public void setOccluded(boolean isOccluded, boolean animate) {
Trace.beginSection("KeyguardViewMediator#setOccluded");
if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
+ mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
mHandler.removeMessages(SET_OCCLUDED);
Message msg = mHandler.obtainMessage(SET_OCCLUDED, isOccluded ? 1 : 0, animate ? 1 : 0);
mHandler.sendMessage(msg);
@@ -2805,6 +2807,7 @@
RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) {
Trace.beginSection("KeyguardViewMediator#startKeyguardExitAnimation");
+ mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
Message msg = mHandler.obtainMessage(START_KEYGUARD_EXIT_ANIM,
new StartKeyguardExitAnimParams(transit, startTime, fadeoutDuration, apps,
wallpapers, nonApps, finishedCallback));
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index ffdd537..510d15b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -137,6 +137,7 @@
private MediaCarouselController mMediaCarouselController;
private final MediaOutputDialogFactory mMediaOutputDialogFactory;
private final FalsingManager mFalsingManager;
+ private final MediaFlags mMediaFlags;
// Used for swipe-to-dismiss logging.
protected boolean mIsImpressed = false;
@@ -155,7 +156,7 @@
Lazy<MediaDataManager> lazyMediaDataManager,
MediaOutputDialogFactory mediaOutputDialogFactory,
MediaCarouselController mediaCarouselController,
- FalsingManager falsingManager, SystemClock systemClock) {
+ FalsingManager falsingManager, MediaFlags mediaFlags, SystemClock systemClock) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
mActivityStarter = activityStarter;
@@ -166,6 +167,7 @@
mMediaOutputDialogFactory = mediaOutputDialogFactory;
mMediaCarouselController = mediaCarouselController;
mFalsingManager = falsingManager;
+ mMediaFlags = mediaFlags;
mSystemClock = systemClock;
loadDimens();
@@ -504,8 +506,9 @@
List<MediaAction> actionIcons = data.getActions();
List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
- // If we got session actions, use those instead
- if (data.getSemanticActions() != null) {
+ // If the session actions flag is enabled, but we're still using the regular layout, use
+ // the session actions anyways
+ if (mMediaFlags.areMediaSessionActionsEnabled() && data.getSemanticActions() != null) {
MediaButton semanticActions = data.getSemanticActions();
actionIcons = new ArrayList<MediaAction>();
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index ea92abd..9e14fe9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -610,8 +610,7 @@
var actionIcons: List<MediaAction> = emptyList()
var actionsToShowCollapsed: List<Int> = emptyList()
var semanticActions: MediaButton? = null
- if (mediaFlags.areMediaSessionActionsEnabled(sbn.packageName, sbn.user.identifier) &&
- mediaController.playbackState != null) {
+ if (mediaFlags.areMediaSessionActionsEnabled() && mediaController.playbackState != null) {
semanticActions = createActionsFromState(sbn.packageName, mediaController)
} else {
val actions = createActionsFromNotification(sbn)
@@ -727,7 +726,7 @@
}
}
- // Finally, assign the remaining button slots: play/pause A B C D
+ // Finally, assign the remaining button slots: C A play/pause B D
// A = previous, else custom action (if not reserved)
// B = next, else custom action (if not reserved)
// C and D are always custom actions
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
index f5200f9..dd35a9a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
@@ -16,7 +16,6 @@
package com.android.systemui.media
-import android.app.StatusBarManager
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -27,17 +26,16 @@
/**
* Check whether media control actions should be based on PlaybackState instead of notification
*/
- fun areMediaSessionActionsEnabled(packageName: String, userId: Int): Boolean {
- val enabled = StatusBarManager.useMediaSessionActionsForApp(packageName, userId)
- // Allow global override with flag
- return enabled || featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS)
+ fun areMediaSessionActionsEnabled(): Boolean {
+ return featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS)
}
/**
* Check whether media controls should use the new session-based layout
*/
fun useMediaSessionLayout(): Boolean {
- return featureFlags.isEnabled(Flags.MEDIA_SESSION_LAYOUT)
+ return featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS) &&
+ featureFlags.isEnabled(Flags.MEDIA_SESSION_LAYOUT)
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 7a4dee2..d472aee 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -812,7 +812,7 @@
@TransformationType
fun calculateTransformationType(): Int {
if (isTransitioningToFullShade) {
- if (inSplitShade) {
+ if (inSplitShade && areGuidedTransitionHostsVisible()) {
return TRANSFORMATION_TYPE_TRANSITION
}
return TRANSFORMATION_TYPE_FADE
@@ -829,6 +829,11 @@
return TRANSFORMATION_TYPE_TRANSITION
}
+ private fun areGuidedTransitionHostsVisible(): Boolean {
+ return getHost(previousLocation)?.visible == true &&
+ getHost(desiredLocation)?.visible == true
+ }
+
/**
* @return the current transformation progress if we're in a guided transformation and -1
* otherwise
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 0b23ad5..a646482 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -119,7 +119,9 @@
mCheckBox.setVisibility(View.GONE);
mStatusIcon.setVisibility(View.GONE);
mContainerLayout.setOnClickListener(null);
- mTitleText.setTextColor(mController.getColorInactiveItem());
+ mTitleText.setTextColor(mController.getColorItemContent());
+ mSubTitleText.setTextColor(mController.getColorItemContent());
+ mTwoLineTitleText.setTextColor(mController.getColorItemContent());
mSeekBar.getProgressDrawable().setColorFilter(
new PorterDuffColorFilter(mController.getColorSeekbarProgress(),
PorterDuff.Mode.SRC_IN));
@@ -140,7 +142,7 @@
&& !mController.hasAdjustVolumeUserRestriction()) {
mProgressBar.getIndeterminateDrawable().setColorFilter(
new PorterDuffColorFilter(
- mController.getColorInactiveItem(),
+ mController.getColorItemContent(),
PorterDuff.Mode.SRC_IN));
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
false /* showSeekBar*/,
@@ -155,7 +157,7 @@
mTitleIcon.setAlpha(DEVICE_CONNECTED_ALPHA);
mStatusIcon.setImageDrawable(
mContext.getDrawable(R.drawable.media_output_status_failed));
- mStatusIcon.setColorFilter(mController.getColorInactiveItem());
+ mStatusIcon.setColorFilter(mController.getColorItemContent());
setTwoLineLayout(device, false /* bFocused */,
false /* showSeekBar */, false /* showProgressBar */,
true /* showSubtitle */, true /* showStatus */);
@@ -163,7 +165,7 @@
mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
} else if (mController.getSelectedMediaDevice().size() > 1
&& isDeviceIncluded(mController.getSelectedMediaDevice(), device)) {
- mTitleText.setTextColor(mController.getColorActiveItem());
+ mTitleText.setTextColor(mController.getColorItemContent());
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
true /* showSeekBar */,
false /* showProgressBar */, false /* showStatus */);
@@ -173,13 +175,13 @@
mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
onCheckBoxClicked(false, device);
});
- setCheckBoxColor(mCheckBox, mController.getColorActiveItem());
+ setCheckBoxColor(mCheckBox, mController.getColorItemContent());
initSeekbar(device);
} else if (!mController.hasAdjustVolumeUserRestriction() && currentlyConnected) {
mStatusIcon.setImageDrawable(
mContext.getDrawable(R.drawable.media_output_status_check));
- mStatusIcon.setColorFilter(mController.getColorActiveItem());
- mTitleText.setTextColor(mController.getColorActiveItem());
+ mStatusIcon.setColorFilter(mController.getColorItemContent());
+ mTitleText.setTextColor(mController.getColorItemContent());
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
true /* showSeekBar */,
false /* showProgressBar */, true /* showStatus */);
@@ -192,7 +194,7 @@
mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
onCheckBoxClicked(true, device);
});
- setCheckBoxColor(mCheckBox, mController.getColorInactiveItem());
+ setCheckBoxColor(mCheckBox, mController.getColorItemContent());
setSingleLineLayout(getItemTitle(device), false /* bFocused */,
false /* showSeekBar */,
false /* showProgressBar */, false /* showStatus */);
@@ -214,7 +216,7 @@
@Override
void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
- mTitleText.setTextColor(mController.getColorInactiveItem());
+ mTitleText.setTextColor(mController.getColorItemContent());
mCheckBox.setVisibility(View.GONE);
setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new),
false /* bFocused */);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 62d5c8e..df0c14b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -170,14 +170,16 @@
void setSingleLineLayout(CharSequence title, boolean bFocused, boolean showSeekBar,
boolean showProgressBar, boolean showStatus) {
mTwoLineLayout.setVisibility(View.GONE);
+ boolean isActive = showSeekBar || showProgressBar;
final Drawable backgroundDrawable =
- showSeekBar || showProgressBar
+ isActive
? mContext.getDrawable(R.drawable.media_output_item_background_active)
.mutate() : mContext.getDrawable(
R.drawable.media_output_item_background)
.mutate();
backgroundDrawable.setColorFilter(new PorterDuffColorFilter(
- mController.getColorItemBackground(),
+ isActive ? mController.getColorConnectedItemBackground()
+ : mController.getColorItemBackground(),
PorterDuff.Mode.SRC_IN));
mItemLayout.setBackground(backgroundDrawable);
mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
@@ -366,7 +368,7 @@
.mutate();
drawable.setColorFilter(
new PorterDuffColorFilter(Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_active_item_main_content),
+ R.color.media_dialog_item_main_content),
PorterDuff.Mode.SRC_IN));
return drawable;
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index a8141c0..dcb1c7c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -216,6 +216,7 @@
PorterDuff.Mode.SRC_IN);
mDoneButton.getBackground().setColorFilter(buttonColorFilter);
mStopButton.getBackground().setColorFilter(buttonColorFilter);
+ mDoneButton.setTextColor(mAdapter.getController().getColorPositiveButtonText());
}
mHeaderIcon.setVisibility(View.VISIBLE);
mHeaderIcon.setImageIcon(icon);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 0b6c68d..ea7f7f2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -110,11 +110,12 @@
private MediaOutputMetricLogger mMetricLogger;
- private int mColorActiveItem;
- private int mColorInactiveItem;
+ private int mColorItemContent;
private int mColorSeekbarProgress;
private int mColorButtonBackground;
private int mColorItemBackground;
+ private int mColorConnectedItemBackground;
+ private int mColorPositiveButtonText;
@Inject
public MediaOutputController(@NonNull Context context, String packageName,
@@ -133,16 +134,18 @@
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
mDialogLaunchAnimator = dialogLaunchAnimator;
mNearbyMediaDevicesManager = nearbyMediaDevicesManagerOptional.orElse(null);
- mColorActiveItem = Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_active_item_main_content);
- mColorInactiveItem = Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_inactive_item_main_content);
+ mColorItemContent = Utils.getColorStateListDefaultColor(mContext,
+ R.color.media_dialog_item_main_content);
mColorSeekbarProgress = Utils.getColorStateListDefaultColor(mContext,
- android.R.color.system_accent1_200);
+ R.color.media_dialog_seekbar_progress);
mColorButtonBackground = Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_item_background);
+ R.color.media_dialog_button_background);
mColorItemBackground = Utils.getColorStateListDefaultColor(mContext,
- android.R.color.system_accent2_50);
+ R.color.media_dialog_item_background);
+ mColorConnectedItemBackground = Utils.getColorStateListDefaultColor(mContext,
+ R.color.media_dialog_connected_item_background);
+ mColorPositiveButtonText = Utils.getColorStateListDefaultColor(mContext,
+ R.color.media_dialog_solid_button_text);
}
void start(@NonNull Callback cb) {
@@ -322,8 +325,7 @@
}
void setColorFilter(Drawable drawable, boolean isActive) {
- drawable.setColorFilter(new PorterDuffColorFilter(isActive
- ? mColorActiveItem : mColorInactiveItem,
+ drawable.setColorFilter(new PorterDuffColorFilter(mColorItemContent,
PorterDuff.Mode.SRC_IN));
}
@@ -358,26 +360,32 @@
ColorScheme mCurrentColorScheme = new ColorScheme(wallpaperColors,
isDarkTheme);
if (isDarkTheme) {
- mColorActiveItem = mCurrentColorScheme.getNeutral1().get(10);
- mColorInactiveItem = mCurrentColorScheme.getNeutral1().get(10);
- mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(2);
- mColorButtonBackground = mCurrentColorScheme.getAccent1().get(2);
- mColorItemBackground = mCurrentColorScheme.getAccent2().get(0);
+ mColorItemContent = mCurrentColorScheme.getAccent1().get(2); // A1-100
+ mColorSeekbarProgress = mCurrentColorScheme.getAccent2().get(7); // A2-600
+ mColorButtonBackground = mCurrentColorScheme.getAccent1().get(4); // A1-300
+ mColorItemBackground = mCurrentColorScheme.getNeutral2().get(9); // N2-800
+ mColorConnectedItemBackground = mCurrentColorScheme.getAccent2().get(9); // A2-800
+ mColorPositiveButtonText = mCurrentColorScheme.getAccent2().get(9); // A2-800
} else {
- mColorActiveItem = mCurrentColorScheme.getNeutral1().get(10);
- mColorInactiveItem = mCurrentColorScheme.getAccent1().get(7);
- mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(3);
- mColorButtonBackground = mCurrentColorScheme.getAccent1().get(3);
- mColorItemBackground = mCurrentColorScheme.getAccent2().get(0);
+ mColorItemContent = mCurrentColorScheme.getAccent1().get(9); // A1-800
+ mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(4); // A1-300
+ mColorButtonBackground = mCurrentColorScheme.getAccent1().get(7); // A1-600
+ mColorItemBackground = mCurrentColorScheme.getAccent2().get(1); // A2-50
+ mColorConnectedItemBackground = mCurrentColorScheme.getAccent1().get(2); // A1-100
+ mColorPositiveButtonText = mCurrentColorScheme.getNeutral1().get(1); // N1-50
}
}
- public int getColorActiveItem() {
- return mColorActiveItem;
+ public int getColorConnectedItemBackground() {
+ return mColorConnectedItemBackground;
}
- public int getColorInactiveItem() {
- return mColorInactiveItem;
+ public int getColorPositiveButtonText() {
+ return mColorPositiveButtonText;
+ }
+
+ public int getColorItemContent() {
+ return mColorItemContent;
}
public int getColorSeekbarProgress() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
index 71cacac..3d5b3a3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
@@ -32,6 +32,7 @@
import android.view.ViewGroup
import android.view.WindowManager
import com.android.internal.widget.CachingIconView
+import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.gesture.TapGestureDetector
@@ -150,40 +151,36 @@
appNameOverride: CharSequence? = null,
) {
val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon)
- appIconView.contentDescription = appNameOverride ?: getAppName(appPackageName)
-
- val appIcon = appIconDrawableOverride ?: getAppIcon(appPackageName)
- val visibility = if (appIcon != null) {
- View.VISIBLE
- } else {
- View.GONE
- }
- appIconView.setImageDrawable(appIcon)
- appIconView.visibility = visibility
+ val appInfo = getAppInfo(appPackageName)
+ appIconView.contentDescription = appNameOverride ?: appInfo.appName
+ appIconView.setImageDrawable(appIconDrawableOverride ?: appInfo.appIcon)
}
- /** Returns the icon of the app playing the media or null if we can't find it. */
- private fun getAppIcon(appPackageName: String?): Drawable? {
- appPackageName ?: return null
- return try {
- context.packageManager.getApplicationIcon(appPackageName)
- } catch (e: PackageManager.NameNotFoundException) {
- Log.w(TAG, "Cannot find icon for package $appPackageName", e)
- null
+ /**
+ * Returns the app name and icon of the app playing media, or a default name and icon if we
+ * can't find the app name/icon.
+ */
+ private fun getAppInfo(appPackageName: String?): AppInfo {
+ if (appPackageName != null) {
+ try {
+ return AppInfo(
+ appName = context.packageManager.getApplicationInfo(
+ appPackageName, PackageManager.ApplicationInfoFlags.of(0)
+ ).loadLabel(context.packageManager).toString(),
+ appIcon = context.packageManager.getApplicationIcon(appPackageName)
+ )
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Cannot find package $appPackageName", e)
+ }
}
- }
-
- /** Returns the name of the app playing the media or null if we can't find it. */
- private fun getAppName(appPackageName: String?): String? {
- appPackageName ?: return null
- return try {
- context.packageManager.getApplicationInfo(
- appPackageName, PackageManager.ApplicationInfoFlags.of(0)
- ).loadLabel(context.packageManager).toString()
- } catch (e: PackageManager.NameNotFoundException) {
- Log.w(TAG, "Cannot find name for package $appPackageName", e)
- null
- }
+ return AppInfo(
+ appName = context.getString(R.string.media_output_dialog_unknown_launch_app_name),
+ appIcon = context.resources.getDrawable(R.drawable.ic_cast).apply {
+ this.setTint(
+ Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary)
+ )
+ }
+ )
}
private fun onScreenTapped(e: MotionEvent) {
@@ -205,3 +202,8 @@
const val REASON_TIMEOUT = "TIMEOUT"
const val REASON_SCREEN_TAP = "SCREEN_TAP"
}
+
+private data class AppInfo(
+ val appName: String,
+ val appIcon: Drawable
+)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index ab4d0dd..de3e89d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -116,6 +116,16 @@
private var scrimTransitionDistance = 0
/**
+ * Distance that it takes in order for the notifications scrim fade in to start.
+ */
+ private var notificationsScrimTransitionDelay = 0
+
+ /**
+ * Distance that it takes for the notifications scrim to fully fade if after it started.
+ */
+ private var notificationsScrimTransitionDistance = 0
+
+ /**
* Distance that the full shade transition takes in order for the notification shelf to fully
* expand.
*/
@@ -225,6 +235,10 @@
R.dimen.lockscreen_shade_transition_by_tap_distance)
scrimTransitionDistance = context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_scrim_transition_distance)
+ notificationsScrimTransitionDelay = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay)
+ notificationsScrimTransitionDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance)
notificationShelfTransitionDistance = context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_notif_shelf_transition_distance)
qsTransitionDistance = context.resources.getDimensionPixelSize(
@@ -405,6 +419,7 @@
false /* animate */, 0 /* delay */)
mediaHierarchyManager.setTransitionToFullShadeAmount(field)
+ transitionToShadeAmountScrim(field)
transitionToShadeAmountCommon(field)
transitionToShadeAmountKeyguard(field)
}
@@ -417,10 +432,15 @@
var qSDragProgress = 0f
private set
- private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
+ private fun transitionToShadeAmountScrim(dragDownAmount: Float) {
val scrimProgress = MathUtils.saturate(dragDownAmount / scrimTransitionDistance)
- scrimController.setTransitionToFullShadeProgress(scrimProgress)
+ val notificationsScrimDragAmount = dragDownAmount - notificationsScrimTransitionDelay
+ val notificationsScrimProgress = MathUtils.saturate(
+ notificationsScrimDragAmount / notificationsScrimTransitionDistance)
+ scrimController.setTransitionToFullShadeProgress(scrimProgress, notificationsScrimProgress)
+ }
+ private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
if (depthControllerTransitionDistance > 0) {
val depthProgress =
MathUtils.saturate(dragDownAmount / depthControllerTransitionDistance)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 3dd717d..eaa66bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -226,10 +226,7 @@
? MathUtils.lerp(shortestWidth, getWidth(), fractionToShade)
: getWidth();
ActivatableNotificationView anv = (ActivatableNotificationView) this;
- NotificationBackgroundView bg = anv.getBackgroundNormal();
- if (bg != null) {
- anv.getBackgroundNormal().setActualWidth((int) actualWidth);
- }
+ anv.setBackgroundWidth((int) actualWidth);
if (mShelfIcons != null) {
mShelfIcons.setActualLayoutWidth((int) actualWidth);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 465ab93..3013ad0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -188,7 +188,7 @@
setContentDescription(state.contentDescription);
int newVisibility = state.visible && !mForceHidden ? View.VISIBLE : View.GONE;
- if (newVisibility != mMobileGroup.getVisibility()) {
+ if (newVisibility != mMobileGroup.getVisibility() && STATE_ICON == mVisibleState) {
mMobileGroup.setVisibility(newVisibility);
needsLayout = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
index 9795dcf..b74140d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
@@ -16,9 +16,12 @@
package com.android.systemui.statusbar.events
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.content.Context
-import android.graphics.Point
+import android.graphics.Rect
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
@@ -30,6 +33,7 @@
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
import com.android.systemui.statusbar.window.StatusBarWindowController
import javax.inject.Inject
+import kotlin.math.roundToInt
/**
* Controls the view for system event animations.
@@ -38,7 +42,7 @@
private val context: Context,
private val statusBarWindowController: StatusBarWindowController,
private val contentInsetsProvider: StatusBarContentInsetsProvider
-) : SystemStatusChipAnimationCallback {
+) : SystemStatusAnimationCallback {
private lateinit var animationWindowView: FrameLayout
@@ -49,90 +53,169 @@
private var chipRight = 0
private var chipLeft = 0
private var chipWidth = 0
- private var dotCenter = Point(0, 0)
+ private var chipMinWidth = context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_chip_min_animation_width)
private var dotSize = context.resources.getDimensionPixelSize(
R.dimen.ongoing_appops_dot_diameter)
- // If the chip animates away to a persistent dot, then we modify the CHIP_OUT animation
- private var isAnimatingToDot = false
+ // Use during animation so that multiple animators can update the drawing rect
+ private var animRect = Rect()
// TODO: move to dagger
private var initialized = false
- override fun onChipAnimationStart(
- viewCreator: ViewCreator,
- @SystemAnimationState state: Int
- ) {
- if (!initialized) init()
+ /**
+ * Give the chip controller a chance to inflate and configure the chip view before we start
+ * animating
+ */
+ fun prepareChipAnimation(viewCreator: ViewCreator) {
+ if (!initialized) {
+ init()
+ }
+ animationDirection = if (animationWindowView.isLayoutRtl) RIGHT else LEFT
- if (state == ANIMATING_IN) {
- animationDirection = if (animationWindowView.isLayoutRtl) RIGHT else LEFT
+ // Initialize the animated view
+ val insets = contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation()
+ currentAnimatedView = viewCreator(context).also {
+ animationWindowView.addView(
+ it.view,
+ layoutParamsDefault(
+ if (animationWindowView.isLayoutRtl) insets.first
+ else insets.second))
+ it.view.alpha = 0f
+ // For some reason, the window view's measured width is always 0 here, so use the
+ // parent (status bar)
+ it.view.measure(
+ View.MeasureSpec.makeMeasureSpec(
+ (animationWindowView.parent as View).width, AT_MOST),
+ View.MeasureSpec.makeMeasureSpec(animationWindowView.height, AT_MOST))
+ chipWidth = it.chipWidth
+ }
- // Initialize the animated view
- val insets = contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation()
- currentAnimatedView = viewCreator(context).also {
- animationWindowView.addView(
- it.view,
- layoutParamsDefault(
- if (animationWindowView.isLayoutRtl) insets.first
- else insets.second))
- it.view.alpha = 0f
- // For some reason, the window view's measured width is always 0 here, so use the
- // parent (status bar)
- it.view.measure(
- View.MeasureSpec.makeMeasureSpec(
- (animationWindowView.parent as View).width, AT_MOST),
- View.MeasureSpec.makeMeasureSpec(animationWindowView.height, AT_MOST))
- chipWidth = it.chipWidth
+ // decide which direction we're animating from, and then set some screen coordinates
+ val contentRect = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation()
+ when (animationDirection) {
+ LEFT -> {
+ chipRight = contentRect.right
+ chipLeft = contentRect.right - chipWidth
}
-
- // decide which direction we're animating from, and then set some screen coordinates
- val contentRect = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation()
- when (animationDirection) {
- LEFT -> {
- chipRight = contentRect.right
- chipLeft = contentRect.right - chipWidth
- }
- else /* RIGHT */ -> {
- chipLeft = contentRect.left
- chipRight = contentRect.left + chipWidth
- }
- }
-
- currentAnimatedView?.apply {
- updateAnimatedViewBoundsForAmount(0.1f, this)
- }
- } else {
- // We are animating away
- currentAnimatedView!!.view.apply {
- alpha = 1f
+ else /* RIGHT */ -> {
+ chipLeft = contentRect.left
+ chipRight = contentRect.left + chipWidth
}
}
}
- override fun onChipAnimationEnd(@SystemAnimationState state: Int) {
- if (state == ANIMATING_IN) {
- // Finished animating in
- currentAnimatedView?.apply {
- updateAnimatedViewBoundsForAmount(1f, this)
- }
- } else {
- // Finished animating away
- currentAnimatedView!!.view.apply {
- visibility = View.INVISIBLE
- }
- animationWindowView.removeView(currentAnimatedView!!.view)
+ override fun onSystemEventAnimationBegin(): Animator {
+ initializeAnimRect()
+
+ val alphaIn = ValueAnimator.ofFloat(0f, 1f).apply {
+ startDelay = 117
+ duration = 83
+ interpolator = null
+ addUpdateListener { currentAnimatedView?.view?.alpha = animatedValue as Float }
}
+ val moveIn = ValueAnimator.ofInt(chipMinWidth, chipWidth).apply {
+ startDelay = 117
+ duration = 383
+ interpolator = STATUS_BAR_X_MOVE_IN
+ addUpdateListener {
+ updateAnimatedViewBoundsWidth(animatedValue as Int)
+ }
+ }
+ val animSet = AnimatorSet()
+ animSet.playTogether(alphaIn, moveIn)
+ return animSet
}
- override fun onChipAnimationUpdate(
- animator: ValueAnimator,
- @SystemAnimationState state: Int
- ) {
- currentAnimatedView?.apply {
- val amt = (animator.animatedValue as Float).amt()
- view.alpha = (animator.animatedValue as Float)
- updateAnimatedViewBoundsForAmount(amt, this)
+ override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator {
+ initializeAnimRect()
+ val finish = if (hasPersistentDot) {
+ createMoveOutAnimationForDot()
+ } else {
+ createMoveOutAnimationDefault()
}
+
+ finish.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ animationWindowView.removeView(currentAnimatedView!!.view)
+ }
+ })
+
+ return finish
+ }
+
+ private fun createMoveOutAnimationForDot(): Animator {
+ val width1 = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply {
+ duration = 150
+ interpolator = STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_1
+ addUpdateListener {
+ updateAnimatedViewBoundsWidth(it.animatedValue as Int)
+ }
+ }
+
+ val width2 = ValueAnimator.ofInt(chipMinWidth, dotSize).apply {
+ startDelay = 150
+ duration = 333
+ interpolator = STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_2
+ addUpdateListener {
+ updateAnimatedViewBoundsWidth(it.animatedValue as Int)
+ }
+ }
+
+ val keyFrame1Height = dotSize * 2
+ val v = currentAnimatedView!!.view
+ val chipVerticalCenter = v.top + v.measuredHeight / 2
+ val height1 = ValueAnimator.ofInt(
+ currentAnimatedView!!.view.measuredHeight, keyFrame1Height).apply {
+ startDelay = 133
+ duration = 100
+ interpolator = STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_1
+ addUpdateListener {
+ updateAnimatedViewBoundsHeight(it.animatedValue as Int, chipVerticalCenter)
+ }
+ }
+
+ val height2 = ValueAnimator.ofInt(keyFrame1Height, dotSize).apply {
+ startDelay = 233
+ duration = 250
+ interpolator = STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_2
+ addUpdateListener {
+ updateAnimatedViewBoundsHeight(it.animatedValue as Int, chipVerticalCenter)
+ }
+ }
+
+ // Move the chip view to overlap exactly with the privacy dot. The chip displays by default
+ // exactly adjacent to the dot, so we can just move over by the diameter of the dot itself
+ val moveOut = ValueAnimator.ofInt(0, dotSize).apply {
+ startDelay = 50
+ duration = 183
+ interpolator = STATUS_CHIP_MOVE_TO_DOT
+ addUpdateListener {
+ // If RTL, we can just invert the move
+ val amt = if (animationDirection == LEFT) {
+ animatedValue as Int
+ } else {
+ -(animatedValue as Int)
+ }
+ updateAnimatedBoundsX(amt)
+ }
+ }
+
+ val animSet = AnimatorSet()
+ animSet.playTogether(width1, width2, height1, height2, moveOut)
+ return animSet
+ }
+
+ private fun createMoveOutAnimationDefault(): Animator {
+ val moveOut = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply {
+ duration = 383
+ addUpdateListener {
+ currentAnimatedView?.apply {
+ updateAnimatedViewBoundsWidth(it.animatedValue as Int)
+ }
+ }
+ }
+ return moveOut
}
private fun init() {
@@ -144,7 +227,6 @@
statusBarWindowController.addViewToWindow(animationWindowView, lp)
animationWindowView.clipToPadding = false
animationWindowView.clipChildren = false
- animationWindowView.measureAllChildren = true
}
private fun layoutParamsDefault(marginEnd: Int): FrameLayout.LayoutParams =
@@ -153,29 +235,55 @@
it.marginEnd = marginEnd
}
- private fun updateAnimatedViewBoundsForAmount(amt: Float, chip: BackgroundAnimatableView) {
+ private fun initializeAnimRect() = animRect.set(
+ chipLeft,
+ currentAnimatedView!!.view.top,
+ chipRight,
+ currentAnimatedView!!.view.bottom)
+
+ /**
+ * To be called during an animation, sets the width and updates the current animated chip view
+ */
+ private fun updateAnimatedViewBoundsWidth(width: Int) {
when (animationDirection) {
LEFT -> {
- chip.setBoundsForAnimation(
- (chipRight - (chipWidth * amt)).toInt(),
- chip.view.top,
- chipRight,
- chip.view.bottom)
- }
- else /* RIGHT */ -> {
- chip.setBoundsForAnimation(
- chipLeft,
- chip.view.top,
- (chipLeft + (chipWidth * amt)).toInt(),
- chip.view.bottom)
+ animRect.set((chipRight - width), animRect.top, chipRight, animRect.bottom)
+ } else /* RIGHT */ -> {
+ animRect.set(chipLeft, animRect.top, (chipLeft + width), animRect.bottom)
}
}
+
+ updateCurrentAnimatedView()
}
- private fun start() = if (animationWindowView.isLayoutRtl) right() else left()
- private fun right() = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation().right
- private fun left() = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation().left
- private fun Float.amt() = 0.01f.coerceAtLeast(this)
+ /**
+ * To be called during an animation, updates the animation rect and sends the update to the chip
+ */
+ private fun updateAnimatedViewBoundsHeight(height: Int, verticalCenter: Int) {
+ animRect.set(
+ animRect.left,
+ verticalCenter - (height.toFloat() / 2).roundToInt(),
+ animRect.right,
+ verticalCenter + (height.toFloat() / 2).roundToInt())
+
+ updateCurrentAnimatedView()
+ }
+
+ /**
+ * To be called during an animation, updates the animation rect offset and updates the chip
+ */
+ private fun updateAnimatedBoundsX(translation: Int) {
+ currentAnimatedView?.view?.translationX = translation.toFloat()
+ }
+
+ /**
+ * To be called during an animation. Sets the chip rect to animRect
+ */
+ private fun updateCurrentAnimatedView() {
+ currentAnimatedView?.setBoundsForAnimation(
+ animRect.left, animRect.top, animRect.right, animRect.bottom
+ )
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
index 947f3eb..36233e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
@@ -19,14 +19,12 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
-import android.animation.ValueAnimator
import android.annotation.IntDef
import android.os.Process
import android.provider.DeviceConfig
import android.util.Log
+import android.view.animation.PathInterpolator
import com.android.systemui.Dumpable
-import com.android.systemui.animation.Interpolators.STANDARD_ACCELERATE
-import com.android.systemui.animation.Interpolators.STANDARD_DECELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
@@ -38,6 +36,7 @@
import com.android.systemui.util.time.SystemClock
import java.io.FileDescriptor
import java.io.PrintWriter
+import java.lang.IllegalStateException
import javax.inject.Inject
@@ -116,7 +115,10 @@
scheduledEvent?.updateFromEvent(event)
if (event.forceVisible) {
hasPersistentDot = true
- notifyTransitionToPersistentDot()
+ // If we missed the chance to show the persistent dot, do it now
+ if (animationState == IDLE) {
+ notifyTransitionToPersistentDot()
+ }
}
} else {
if (DEBUG) {
@@ -162,68 +164,90 @@
return
}
- // Schedule the animation to start after a debounce period
- cancelExecutionRunnable = executor.executeDelayed({
- cancelExecutionRunnable = null
- animationState = ANIMATING_IN
- statusBarWindowController.setForceStatusBarVisible(true)
+ chipAnimationController.prepareChipAnimation(scheduledEvent!!.viewCreator)
+ animationState = ANIMATION_QUEUED
+ executor.executeDelayed({
+ runChipAnimation()
+ }, DEBOUNCE_DELAY)
+ }
- val entranceAnimator = ValueAnimator.ofFloat(1f, 0f)
- entranceAnimator.duration = ENTRANCE_ANIM_LENGTH
- entranceAnimator.addListener(systemAnimatorAdapter)
- entranceAnimator.addUpdateListener(systemUpdateListener)
- entranceAnimator.interpolator = STANDARD_ACCELERATE
+ /**
+ * 1. Define a total budget for the chip animation (1500ms)
+ * 2. Send out callbacks to listeners so that they can generate animations locally
+ * 3. Update the scheduler state so that clients know where we are
+ * 4. Maybe: provide scaffolding such as: dot location, margins, etc
+ * 5. Maybe: define a maximum animation length and enforce it. Probably only doable if we
+ * collect all of the animators and run them together.
+ */
+ private fun runChipAnimation() {
+ statusBarWindowController.setForceStatusBarVisible(true)
+ animationState = ANIMATING_IN
- val chipAnimator = ValueAnimator.ofFloat(0f, 1f)
- chipAnimator.duration = CHIP_ANIM_LENGTH
- chipAnimator.addListener(
- ChipAnimatorAdapter(RUNNING_CHIP_ANIM, scheduledEvent!!.viewCreator))
- chipAnimator.addUpdateListener(chipUpdateListener)
- chipAnimator.interpolator = STANDARD_DECELERATE
+ val animSet = collectStartAnimations()
+ if (animSet.totalDuration > 500) {
+ throw IllegalStateException("System animation total length exceeds budget. " +
+ "Expected: 500, actual: ${animSet.totalDuration}")
+ }
+ animSet.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ animationState = RUNNING_CHIP_ANIM
+ }
+ })
+ animSet.start()
- val aSet2 = AnimatorSet()
- aSet2.playSequentially(entranceAnimator, chipAnimator)
- aSet2.start()
-
- executor.executeDelayed({
- animationState = ANIMATING_OUT
-
- val systemAnimator = ValueAnimator.ofFloat(0f, 1f)
- systemAnimator.duration = ENTRANCE_ANIM_LENGTH
- systemAnimator.addListener(systemAnimatorAdapter)
- systemAnimator.addUpdateListener(systemUpdateListener)
- systemAnimator.interpolator = STANDARD_DECELERATE
- systemAnimator.addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- statusBarWindowController.setForceStatusBarVisible(false)
+ executor.executeDelayed({
+ val animSet2 = collectFinishAnimations()
+ animationState = ANIMATING_OUT
+ animSet2.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ animationState = if (hasPersistentDot) {
+ SHOWING_PERSISTENT_DOT
+ } else {
+ IDLE
}
- })
- val chipAnimator = ValueAnimator.ofFloat(1f, 0f)
- chipAnimator.duration = CHIP_ANIM_LENGTH
- val endState = if (hasPersistentDot) {
- SHOWING_PERSISTENT_DOT
- } else {
- IDLE
+ statusBarWindowController.setForceStatusBarVisible(false)
}
- chipAnimator.addListener(
- ChipAnimatorAdapter(endState, scheduledEvent!!.viewCreator))
- chipAnimator.addUpdateListener(chipUpdateListener)
- chipAnimator.interpolator = STANDARD_ACCELERATE
+ })
+ animSet2.start()
+ scheduledEvent = null
+ }, DISPLAY_LENGTH)
+ }
- val aSet2 = AnimatorSet()
+ private fun collectStartAnimations(): AnimatorSet {
+ val animators = mutableListOf<Animator>()
+ listeners.forEach { listener ->
+ listener.onSystemEventAnimationBegin()?.let { anim ->
+ animators.add(anim)
+ }
+ }
+ animators.add(chipAnimationController.onSystemEventAnimationBegin())
+ val animSet = AnimatorSet().also {
+ it.playTogether(animators)
+ }
- aSet2.play(chipAnimator).before(systemAnimator)
- if (hasPersistentDot) {
- val dotAnim = notifyTransitionToPersistentDot()
- if (dotAnim != null) aSet2.playTogether(systemAnimator, dotAnim)
- }
+ return animSet
+ }
- aSet2.start()
+ private fun collectFinishAnimations(): AnimatorSet {
+ val animators = mutableListOf<Animator>()
+ listeners.forEach { listener ->
+ listener.onSystemEventAnimationFinish(hasPersistentDot)?.let { anim ->
+ animators.add(anim)
+ }
+ }
+ animators.add(chipAnimationController.onSystemEventAnimationFinish(hasPersistentDot))
+ if (hasPersistentDot) {
+ val dotAnim = notifyTransitionToPersistentDot()
+ if (dotAnim != null) {
+ animators.add(dotAnim)
+ }
+ }
+ val animSet = AnimatorSet().also {
+ it.playTogether(animators)
+ }
- scheduledEvent = null
- }, DISPLAY_LENGTH)
- }, DELAY)
+ return animSet
}
private fun notifyTransitionToPersistentDot(): Animator? {
@@ -257,18 +281,6 @@
return null
}
- private fun notifySystemStart() {
- listeners.forEach { it.onSystemChromeAnimationStart() }
- }
-
- private fun notifySystemFinish() {
- listeners.forEach { it.onSystemChromeAnimationEnd() }
- }
-
- private fun notifySystemAnimationUpdate(anim: ValueAnimator) {
- listeners.forEach { it.onSystemChromeAnimationUpdate(anim) }
- }
-
override fun addCallback(listener: SystemStatusAnimationCallback) {
Assert.isMainThread()
@@ -287,24 +299,6 @@
}
}
- private val systemUpdateListener = ValueAnimator.AnimatorUpdateListener {
- anim -> notifySystemAnimationUpdate(anim)
- }
-
- private val systemAnimatorAdapter = object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(p0: Animator?) {
- notifySystemFinish()
- }
-
- override fun onAnimationStart(p0: Animator?) {
- notifySystemStart()
- }
- }
-
- private val chipUpdateListener = ValueAnimator.AnimatorUpdateListener {
- anim -> chipAnimationController.onChipAnimationUpdate(anim, animationState)
- }
-
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
pw.println("Scheduled event: $scheduledEvent")
pw.println("Has persistent privacy dot: $hasPersistentDot")
@@ -318,24 +312,6 @@
}
}
}
-
- inner class ChipAnimatorAdapter(
- @SystemAnimationState val endState: Int,
- val viewCreator: ViewCreator
- ) : AnimatorListenerAdapter() {
- override fun onAnimationEnd(p0: Animator?) {
- chipAnimationController.onChipAnimationEnd(animationState)
- animationState = if (endState == SHOWING_PERSISTENT_DOT && !hasPersistentDot) {
- IDLE
- } else {
- endState
- }
- }
-
- override fun onAnimationStart(p0: Animator?) {
- chipAnimationController.onChipAnimationStart(viewCreator, animationState)
- }
- }
}
/**
@@ -344,16 +320,14 @@
* create space for the chip animation to display. This means hiding the system elements in the
* status bar and keyguard.
*
- * TODO: the chip animation really only has one client, we can probably remove it from this
- * interface
- *
* The value animators themselves are simple animators from 0.0 to 1.0. Listeners can apply any
* interpolation they choose but realistically these are most likely to be simple alpha transitions
*/
interface SystemStatusAnimationCallback {
- @JvmDefault fun onSystemChromeAnimationUpdate(animator: ValueAnimator) {}
- @JvmDefault fun onSystemChromeAnimationStart() {}
- @JvmDefault fun onSystemChromeAnimationEnd() {}
+ /** Implement this method to return an [Animator] or [AnimatorSet] that presents the chip */
+ fun onSystemEventAnimationBegin(): Animator? { return null }
+ /** Implement this method to return an [Animator] or [AnimatorSet] that hides the chip */
+ fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator? { return null }
// Best method name, change my mind
@JvmDefault
@@ -363,50 +337,61 @@
@JvmDefault fun onHidePersistentDot(): Animator? { return null }
}
-interface SystemStatusChipAnimationCallback {
- fun onChipAnimationUpdate(animator: ValueAnimator, @SystemAnimationState state: Int) {}
-
- fun onChipAnimationStart(
- viewCreator: ViewCreator,
- @SystemAnimationState state: Int
- ) {}
-
- fun onChipAnimationEnd(@SystemAnimationState state: Int) {}
-}
-
/**
+ * Animation state IntDef
*/
@Retention(AnnotationRetention.SOURCE)
@IntDef(
value = [
- IDLE, ANIMATING_IN, RUNNING_CHIP_ANIM, ANIMATING_OUT, SHOWING_PERSISTENT_DOT
+ IDLE,
+ ANIMATION_QUEUED,
+ ANIMATING_IN,
+ RUNNING_CHIP_ANIM,
+ ANIMATING_OUT,
+ SHOWING_PERSISTENT_DOT
]
)
annotation class SystemAnimationState
/** No animation is in progress */
const val IDLE = 0
+/** An animation is queued, and awaiting the debounce period */
+const val ANIMATION_QUEUED = 1
/** System is animating out, and chip is animating in */
-const val ANIMATING_IN = 1
+const val ANIMATING_IN = 2
/** Chip has animated in and is awaiting exit animation, and optionally playing its own animation */
-const val RUNNING_CHIP_ANIM = 2
+const val RUNNING_CHIP_ANIM = 3
/** Chip is animating away and system is animating back */
-const val ANIMATING_OUT = 3
+const val ANIMATING_OUT = 4
/** Chip has animated away, and the persistent dot is showing */
-const val SHOWING_PERSISTENT_DOT = 4
+const val SHOWING_PERSISTENT_DOT = 5
+
+/** Commonly-needed interpolators can go here */
+@JvmField val STATUS_BAR_X_MOVE_OUT = PathInterpolator(0.33f, 0f, 0f, 1f)
+@JvmField val STATUS_BAR_X_MOVE_IN = PathInterpolator(0f, 0f, 0f, 1f)
+/**
+ * Status chip animation to dot have multiple stages of motion, the _1 and _2 interpolators should
+ * be used in succession
+ */
+val STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_1 = PathInterpolator(0.44f, 0f, 0.25f, 1f)
+val STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_2 = PathInterpolator(0.3f, 0f, 0.26f, 1f)
+val STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_1 = PathInterpolator(0.4f, 0f, 0.17f, 1f)
+val STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_2 = PathInterpolator(0.3f, 0f, 0f, 1f)
+val STATUS_CHIP_MOVE_TO_DOT = PathInterpolator(0f, 0f, 0.05f, 1f)
private const val TAG = "SystemStatusAnimationScheduler"
-private const val DELAY = 0L
+private const val DEBOUNCE_DELAY = 100L
/**
- * The total time spent animation should be 1500ms. The entrance animation is how much time
- * we give to the system to animate system elements out of the way. Total chip animation length
- * will be equivalent to 2*chip_anim_length + display_length
+ * The total time spent on the chip animation is 1500ms, broken up into 3 sections:
+ * - 500ms to animate the chip in (including animating system icons away)
+ * - 500ms holding the chip on screen
+ * - 500ms to animate the chip away (and system icons back)
+ *
+ * So DISPLAY_LENGTH should be the sum of the first 2 phases, while the final 500ms accounts for
+ * the actual animation
*/
-private const val ENTRANCE_ANIM_LENGTH = 250L
-private const val CHIP_ANIM_LENGTH = 250L
-// 1s + entrance time + chip anim_length
-private const val DISPLAY_LENGTH = 1500L
+private const val DISPLAY_LENGTH = 1000L
private const val MIN_UPTIME: Long = 5 * 1000
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index 7fbb0f1..02aa1f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -25,7 +25,7 @@
@JvmOverloads
fun getAnimatorController(
notification: ExpandableNotificationRow,
- onFinishAnimationCallback: Runnable = Runnable {}
+ onFinishAnimationCallback: Runnable? = null
): NotificationLaunchAnimatorController {
return NotificationLaunchAnimatorController(
notificationShadeWindowViewController,
@@ -49,7 +49,7 @@
private val headsUpManager: HeadsUpManagerPhone,
private val notification: ExpandableNotificationRow,
private val jankMonitor: InteractionJankMonitor,
- private val onFinishAnimationCallback: Runnable
+ private val onFinishAnimationCallback: Runnable?
) : ActivityLaunchAnimator.Controller {
companion object {
@@ -123,7 +123,7 @@
if (!willAnimate) {
removeHun(animate = true)
- onFinishAnimationCallback.run()
+ onFinishAnimationCallback?.run()
}
}
@@ -142,7 +142,7 @@
notificationShadeWindowViewController.setExpandAnimationRunning(false)
notificationEntry.isExpandAnimationRunning = false
removeHun(animate = true)
- onFinishAnimationCallback.run()
+ onFinishAnimationCallback?.run()
}
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -162,7 +162,7 @@
notificationListContainer.setExpandingNotification(null)
applyParams(null)
removeHun(animate = false)
- onFinishAnimationCallback.run()
+ onFinishAnimationCallback?.run()
}
private fun applyParams(params: ExpandAnimationParameters?) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index fca2aa1..577d536 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -163,10 +163,13 @@
}
/**
- * @return The background of this view.
+ * @param width The actual width to apply to the background view.
*/
- public NotificationBackgroundView getBackgroundNormal() {
- return mBackgroundNormal;
+ public void setBackgroundWidth(int width) {
+ if (mBackgroundNormal == null) {
+ return;
+ }
+ mBackgroundNormal.setActualWidth(width);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index c237e1d..e479509 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -79,7 +79,6 @@
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.CallLayout;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.FalsingCollector;
@@ -90,6 +89,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
@@ -111,10 +111,11 @@
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.SwipeableView;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.Compile;
import com.android.systemui.util.DumpUtilsKt;
@@ -169,6 +170,7 @@
private RowContentBindStage mRowContentBindStage;
private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
private Optional<BubblesManager> mBubblesManagerOptional;
+ private MetricsLogger mMetricsLogger;
private int mIconTransformContentShift;
private int mMaxHeadsUpHeightBeforeN;
private int mMaxHeadsUpHeightBeforeP;
@@ -304,8 +306,7 @@
final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
boolean nowExpanded = mGroupExpansionManager.toggleGroupExpansion(mEntry);
mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded);
- MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
- nowExpanded);
+ mMetricsLogger.action(MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER, nowExpanded);
onExpansionChanged(true /* userAction */, wasExpanded);
} else if (mEnableNonGroupedNotificationExpand) {
if (v.isAccessibilityFocused()) {
@@ -327,8 +328,7 @@
}
notifyHeightChanged(true);
mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded);
- MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
- nowExpanded);
+ mMetricsLogger.action(MetricsEvent.ACTION_NOTIFICATION_EXPANDER, nowExpanded);
}
}
};
@@ -1271,7 +1271,7 @@
addView(mMenuRow.getMenuView(), menuIndex);
}
for (NotificationContentView l : mLayouts) {
- l.initView();
+ l.reinflate();
l.reInflateViews();
}
mEntry.getSbn().clearPackageContext();
@@ -1464,7 +1464,7 @@
* @param fromAccessibility whether this dismiss is coming from an accessibility action
*/
public void performDismiss(boolean fromAccessibility) {
- Dependency.get(MetricsLogger.class).count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
+ mMetricsLogger.count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
dismiss(fromAccessibility);
if (mEntry.isDismissable()) {
if (mOnUserInteractionCallback != null) {
@@ -1600,7 +1600,10 @@
PeopleNotificationIdentifier peopleNotificationIdentifier,
OnUserInteractionCallback onUserInteractionCallback,
Optional<BubblesManager> bubblesManagerOptional,
- NotificationGutsManager gutsManager) {
+ NotificationGutsManager gutsManager,
+ MetricsLogger metricsLogger,
+ SmartReplyConstants smartReplyConstants,
+ SmartReplyController smartReplyController) {
mEntry = entry;
mAppName = appName;
if (mMenuRow == null) {
@@ -1623,15 +1626,18 @@
mFalsingManager = falsingManager;
mFalsingCollector = falsingCollector;
mStatusBarStateController = statusBarStateController;
-
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
for (NotificationContentView l : mLayouts) {
- l.setPeopleNotificationIdentifier(mPeopleNotificationIdentifier);
- l.setRemoteInputViewSubcomponentFactory(rivSubcomponentFactory);
+ l.initialize(
+ mPeopleNotificationIdentifier,
+ rivSubcomponentFactory,
+ smartReplyConstants,
+ smartReplyController);
}
mOnUserInteractionCallback = onUserInteractionCallback;
mBubblesManagerOptional = bubblesManagerOptional;
mNotificationGutsManager = gutsManager;
+ mMetricsLogger = metricsLogger;
cacheIsSystemNotification();
}
@@ -3127,7 +3133,7 @@
if (mGroupMembershipManager.isGroupSummary(mEntry)) {
event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
}
- MetricsLogger.action(mContext, event, userExpanded);
+ mMetricsLogger.action(event, userExpanded);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index c4beb5b..599039d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -27,6 +27,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
@@ -35,6 +36,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.FeedbackIcon;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
@@ -49,6 +51,7 @@
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.time.SystemClock;
import com.android.systemui.wmshell.BubblesManager;
@@ -82,6 +85,7 @@
private final HeadsUpManager mHeadsUpManager;
private final ExpandableNotificationRow.OnExpandClickListener mOnExpandClickListener;
private final StatusBarStateController mStatusBarStateController;
+ private final MetricsLogger mMetricsLogger;
private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
this::logNotificationExpansion;
@@ -94,16 +98,21 @@
private final boolean mAllowLongPress;
private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
private final Optional<BubblesManager> mBubblesManagerOptional;
+ private final SmartReplyConstants mSmartReplyConstants;
+ private final SmartReplyController mSmartReplyController;
private final ExpandableNotificationRowDragController mDragController;
@Inject
public ExpandableNotificationRowController(
ExpandableNotificationRow view,
- NotificationListContainer listContainer,
- RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
ActivatableNotificationViewController activatableNotificationViewController,
+ RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
+ MetricsLogger metricsLogger,
+ NotificationListContainer listContainer,
NotificationMediaManager mediaManager,
+ SmartReplyConstants smartReplyConstants,
+ SmartReplyController smartReplyController,
PluginManager pluginManager,
SystemClock clock,
@AppName String appName,
@@ -152,6 +161,9 @@
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
mBubblesManagerOptional = bubblesManagerOptional;
mDragController = dragController;
+ mMetricsLogger = metricsLogger;
+ mSmartReplyConstants = smartReplyConstants;
+ mSmartReplyController = smartReplyController;
}
/**
@@ -179,7 +191,10 @@
mPeopleNotificationIdentifier,
mOnUserInteractionCallback,
mBubblesManagerOptional,
- mNotificationGutsManager
+ mNotificationGutsManager,
+ mMetricsLogger,
+ mSmartReplyConstants,
+ mSmartReplyController
);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index adb4ce6..b9c71132 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -39,7 +39,6 @@
import android.widget.LinearLayout;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.RemoteInputController;
@@ -94,7 +93,6 @@
private final Rect mClipBounds = new Rect();
private int mMinContractedHeight;
- private int mNotificationContentMarginEnd;
private View mContractedChild;
private View mExpandedChild;
private View mHeadsUpChild;
@@ -116,7 +114,7 @@
private NotificationViewWrapper mContractedWrapper;
private NotificationViewWrapper mExpandedWrapper;
private NotificationViewWrapper mHeadsUpWrapper;
- private HybridGroupManager mHybridGroupManager;
+ private final HybridGroupManager mHybridGroupManager;
private int mClipTopAmount;
private int mContentHeight;
private int mVisibleType = VISIBLE_TYPE_NONE;
@@ -128,7 +126,6 @@
private int mHeadsUpHeight;
private int mNotificationMaxHeight;
private NotificationEntry mNotificationEntry;
- private GroupMembershipManager mGroupMembershipManager;
private RemoteInputController mRemoteInputController;
private Runnable mExpandedVisibleListener;
private PeopleNotificationIdentifier mPeopleIdentifier;
@@ -184,7 +181,6 @@
private boolean mFocusOnVisibilityChange;
private boolean mHeadsUpAnimatingAway;
private int mClipBottomAmount;
- private boolean mIsLowPriority;
private boolean mIsContentExpandable;
private boolean mRemoteInputVisible;
private int mUnrestrictedContentHeight;
@@ -192,16 +188,23 @@
public NotificationContentView(Context context, AttributeSet attrs) {
super(context, attrs);
mHybridGroupManager = new HybridGroupManager(getContext());
- mSmartReplyConstants = Dependency.get(SmartReplyConstants.class);
- mSmartReplyController = Dependency.get(SmartReplyController.class);
- initView();
+ reinflate();
}
- public void initView() {
+ public void initialize(
+ PeopleNotificationIdentifier peopleNotificationIdentifier,
+ RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
+ SmartReplyConstants smartReplyConstants,
+ SmartReplyController smartReplyController) {
+ mPeopleIdentifier = peopleNotificationIdentifier;
+ mRemoteInputSubcomponentFactory = rivSubcomponentFactory;
+ mSmartReplyConstants = smartReplyConstants;
+ mSmartReplyController = smartReplyController;
+ }
+
+ public void reinflate() {
mMinContractedHeight = getResources().getDimensionPixelSize(
R.dimen.min_notification_layout_height);
- mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_content_margin_end);
}
public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
@@ -1606,7 +1609,6 @@
}
public void setGroupMembershipManager(GroupMembershipManager groupMembershipManager) {
- mGroupMembershipManager = groupMembershipManager;
}
public void setRemoteInputController(RemoteInputController r) {
@@ -1694,10 +1696,6 @@
mContainingNotification = containingNotification;
}
- public void setPeopleNotificationIdentifier(PeopleNotificationIdentifier peopleIdentifier) {
- mPeopleIdentifier = peopleIdentifier;
- }
-
public void requestSelectLayout(boolean needsAnimation) {
selectLayout(needsAnimation, false);
}
@@ -1865,7 +1863,6 @@
}
public void setIsLowPriority(boolean isLowPriority) {
- mIsLowPriority = isLowPriority;
}
public boolean isDimmable() {
@@ -2090,10 +2087,6 @@
return false;
}
- public void setRemoteInputViewSubcomponentFactory(RemoteInputViewSubcomponent.Factory factory) {
- mRemoteInputSubcomponentFactory = factory;
- }
-
private static class RemoteInputViewData {
@Nullable RemoteInputView mView;
@Nullable RemoteInputViewController mController;
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 27cc326..ade95a8 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
@@ -782,6 +782,14 @@
y = (int) (mAmbientState.getStackY() + mAmbientState.getStackHeight());
drawDebugInfo(canvas, y, Color.BLUE,
/* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight() = "+y);
+
+ y = (int) mAmbientState.getStackY() + mContentHeight;
+ drawDebugInfo(canvas, y, Color.MAGENTA,
+ /* label= */ "mAmbientState.getStackY() + mContentHeight = " + y);
+
+ y = (int) mAmbientState.getStackY() + mIntrinsicContentHeight;
+ drawDebugInfo(canvas, y, Color.YELLOW,
+ /* label= */ "mAmbientState.getStackY() + mIntrinsicContentHeight = " + y);
}
private void drawDebugInfo(Canvas canvas, int y, int color, String label) {
@@ -1293,14 +1301,13 @@
mOnStackYChanged.accept(listenerNeedsAnimation);
}
if (mQsExpansionFraction <= 0 && !shouldSkipHeightUpdate()) {
- final float endHeight = updateStackEndHeight(
- getHeight(), getEmptyBottomMargin(), mTopPadding);
+ final float endHeight = updateStackEndHeight();
updateStackHeight(endHeight, fraction);
}
}
- public float updateStackEndHeight(float height, float bottomMargin, float topPadding) {
- final float stackEndHeight = Math.max(0f, height - bottomMargin - topPadding);
+ private float updateStackEndHeight() {
+ final float stackEndHeight = Math.max(0f, mIntrinsicContentHeight);
mAmbientState.setStackEndHeight(stackEndHeight);
return stackEndHeight;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 65173a2..cb332bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -174,7 +174,7 @@
}
private void updateKeyguardStatusBarHeight() {
- MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
+ MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
lp.height = getStatusBarHeaderHeightKeyguard(mContext);
setLayoutParams(lp);
}
@@ -510,28 +510,6 @@
}
}
- void onSystemChromeAnimationStart(boolean isAnimatingOut) {
- if (isAnimatingOut) {
- mSystemIconsContainer.setVisibility(View.VISIBLE);
- mSystemIconsContainer.setAlpha(0f);
- }
- }
-
- void onSystemChromeAnimationEnd(boolean isAnimatingIn) {
- // Make sure the system icons are out of the way
- if (isAnimatingIn) {
- mSystemIconsContainer.setVisibility(View.INVISIBLE);
- mSystemIconsContainer.setAlpha(0f);
- } else {
- mSystemIconsContainer.setAlpha(1f);
- mSystemIconsContainer.setVisibility(View.VISIBLE);
- }
- }
-
- void onSystemChromeAnimationUpdate(float animatedValue) {
- mSystemIconsContainer.setAlpha(animatedValue);
- }
-
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 1df1aff..af4fb8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -17,8 +17,6 @@
package com.android.systemui.statusbar.phone;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -47,6 +45,7 @@
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventAnimator;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserInfoTracker;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherFeatureController;
@@ -107,6 +106,8 @@
@Override
public void onDensityOrFontScaleChanged() {
mView.loadDimens();
+ // The animator is dependent on resources for offsets
+ mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, getResources());
}
@Override
@@ -123,21 +124,16 @@
private final SystemStatusAnimationCallback mAnimationCallback =
new SystemStatusAnimationCallback() {
+ @NonNull
@Override
- public void onSystemChromeAnimationStart() {
- mView.onSystemChromeAnimationStart(
- mAnimationScheduler.getAnimationState() == ANIMATING_OUT);
+ public Animator onSystemEventAnimationFinish(boolean hasPersistentDot) {
+ return mSystemEventAnimator.onSystemEventAnimationFinish(hasPersistentDot);
}
+ @NonNull
@Override
- public void onSystemChromeAnimationEnd() {
- mView.onSystemChromeAnimationEnd(
- mAnimationScheduler.getAnimationState() == ANIMATING_IN);
- }
-
- @Override
- public void onSystemChromeAnimationUpdate(@NonNull ValueAnimator anim) {
- mView.onSystemChromeAnimationUpdate((float) anim.getAnimatedValue());
+ public Animator onSystemEventAnimationBegin() {
+ return mSystemEventAnimator.onSystemEventAnimationBegin();
}
};
@@ -232,6 +228,7 @@
private int mStatusBarState;
private boolean mDozing;
private boolean mShowingKeyguardHeadsUp;
+ private StatusBarSystemEventAnimator mSystemEventAnimator;
@Inject
public KeyguardStatusBarViewController(
@@ -302,6 +299,7 @@
mView.setKeyguardUserAvatarEnabled(
!mFeatureController.isStatusBarUserSwitcherFeatureEnabled());
mFeatureController.addCallback(enabled -> mView.setKeyguardUserAvatarEnabled(!enabled));
+ mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, r);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 24f5ff8..78edc07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -445,7 +445,7 @@
mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_UNLOCK);
}
@Classifier.InteractionType int interactionType = vel == 0 ? GENERIC
- : vel > 0 ? QUICK_SETTINGS
+ : y - mInitialTouchY > 0 ? QUICK_SETTINGS
: (mKeyguardStateController.canDismissLockScreen()
? UNLOCK : BOUNCER_UNLOCK);
@@ -532,7 +532,7 @@
return true;
}
- @Classifier.InteractionType int interactionType = vel > 0
+ @Classifier.InteractionType int interactionType = y - mInitialTouchY > 0
? QUICK_SETTINGS : (
mKeyguardStateController.canDismissLockScreen() ? UNLOCK : BOUNCER_UNLOCK);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 419661b7..1ad365b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -116,6 +116,15 @@
private float mTransitionToFullShadeProgress;
/**
+ * Same as {@link #mTransitionToFullShadeProgress}, but specifically for the notifications scrim
+ * on the lock screen.
+ *
+ * On split shade lock screen we want the different scrims to fade in at different times and
+ * rates.
+ */
+ private float mTransitionToLockScreenFullShadeNotificationsProgress;
+
+ /**
* If we're currently transitioning to the full shade.
*/
private boolean mTransitioningToFullShade;
@@ -574,11 +583,17 @@
* Set the amount of progress we are currently in if we're transitioning to the full shade.
* 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
* shade.
+ *
+ * @param progress the progress for all scrims.
+ * @param lockScreenNotificationsProgress the progress specifically for the notifications scrim.
*/
- public void setTransitionToFullShadeProgress(float progress) {
- if (progress != mTransitionToFullShadeProgress) {
+ public void setTransitionToFullShadeProgress(float progress,
+ float lockScreenNotificationsProgress) {
+ if (progress != mTransitionToFullShadeProgress || lockScreenNotificationsProgress
+ != mTransitionToLockScreenFullShadeNotificationsProgress) {
mTransitionToFullShadeProgress = progress;
- setTransitionToFullShade(progress > 0.0f);
+ mTransitionToLockScreenFullShadeNotificationsProgress = lockScreenNotificationsProgress;
+ setTransitionToFullShade(progress > 0.0f || lockScreenNotificationsProgress > 0.0f);
applyAndDispatchState();
}
}
@@ -754,12 +769,13 @@
} else {
mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
}
- if (mState == ScrimState.KEYGUARD && mTransitionToFullShadeProgress > 0.0f) {
+ if (mState == ScrimState.KEYGUARD
+ && mTransitionToLockScreenFullShadeNotificationsProgress > 0.0f) {
// Interpolate the notification alpha when transitioning!
mNotificationsAlpha = MathUtils.lerp(
mNotificationsAlpha,
getInterpolatedFraction(),
- mTransitionToFullShadeProgress);
+ mTransitionToLockScreenFullShadeNotificationsProgress);
}
mNotificationsTint = mState.getNotifTint();
mBehindTint = behindTint;
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 637e4be..6fe92fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -397,15 +397,25 @@
mMainThreadHandler.post(() -> {
final Runnable removeNotification = () -> {
mOnUserInteractionCallback.onDismiss(entry, REASON_CLICK, summaryToRemove);
+ if (!animate) {
+ // If we're animating, this would be invoked after the activity launch
+ // animation completes. Since we're not animating, the launch already
+ // happened synchronously, so we notify the launch is complete here after
+ // onDismiss.
+ mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
+ }
};
if (mPresenter.isCollapsing()) {
- // To avoid lags we're only performing the remove
- // after the shade is collapsed
+ // To avoid lags we're only performing the remove after the shade is collapsed
mShadeController.addPostCollapseAction(removeNotification);
} else {
removeNotification.run();
}
});
+ } else if (!canBubble && !animate) {
+ // Not animating, this is the end of the launch flow (see above comment for more info).
+ mMainThreadHandler.post(
+ () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
}
mIsCollapsingToShowActivityOverLockscreen = false;
@@ -481,8 +491,9 @@
boolean isActivityIntent) {
mLogger.logStartNotificationIntent(entry.getKey(), intent);
try {
- Runnable onFinishAnimationCallback =
- () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
+ Runnable onFinishAnimationCallback = animate
+ ? () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry)
+ : null;
ActivityLaunchAnimator.Controller animationController =
new StatusBarLaunchAnimatorController(
mNotificationAnimationProvider
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 2c84219..33bc401 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -20,12 +20,10 @@
import static android.app.StatusBarManager.DISABLE_ONGOING_CALL_CHIP;
import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.IDLE;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.SHOWING_PERSISTENT_DOT;
-import android.animation.ValueAnimator;
+import android.animation.Animator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -136,6 +134,7 @@
}
};
private OperatorNameViewController mOperatorNameViewController;
+ private StatusBarSystemEventAnimator mSystemEventAnimator;
@SuppressLint("ValidFragment")
public CollapsedStatusBarFragment(
@@ -210,7 +209,8 @@
initEmergencyCryptkeeperText();
initOperatorName();
initNotificationIconArea();
- mAnimationScheduler.addCallback(this);
+ mSystemEventAnimator =
+ new StatusBarSystemEventAnimator(mSystemIconArea, getResources());
}
@VisibleForTesting
@@ -245,6 +245,7 @@
mCommandQueue.addCallback(this);
mStatusBarStateController.addCallback(this);
initOngoingCallChip();
+ mAnimationScheduler.addCallback(this);
mSecureSettings.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON),
@@ -258,6 +259,7 @@
mCommandQueue.removeCallback(this);
mStatusBarStateController.removeCallback(this);
mOngoingCallController.removeCallback(mOngoingCallListener);
+ mAnimationScheduler.removeCallback(this);
mSecureSettings.unregisterContentObserver(mVolumeSettingObserver);
}
@@ -265,7 +267,6 @@
public void onDestroyView() {
super.onDestroyView();
mStatusBarIconController.removeIconGroup(mDarkIconManager);
- mAnimationScheduler.removeCallback(this);
if (mNetworkController.hasEmergencyCryptKeeperText()) {
mNetworkController.removeCallback(mSignalCallback);
}
@@ -576,35 +577,16 @@
disable(getContext().getDisplayId(), mDisabled1, mDisabled2, false /* animate */);
}
+ @Nullable
@Override
- public void onSystemChromeAnimationStart() {
- if (mAnimationScheduler.getAnimationState() == ANIMATING_OUT
- && !isSystemIconAreaDisabled()) {
- mSystemIconArea.setVisibility(View.VISIBLE);
- mSystemIconArea.setAlpha(0f);
- }
+ public Animator onSystemEventAnimationBegin() {
+ return mSystemEventAnimator.onSystemEventAnimationBegin();
}
+ @Nullable
@Override
- public void onSystemChromeAnimationEnd() {
- // Make sure the system icons are out of the way
- if (mAnimationScheduler.getAnimationState() == ANIMATING_IN) {
- mSystemIconArea.setVisibility(View.INVISIBLE);
- mSystemIconArea.setAlpha(0f);
- } else {
- if (isSystemIconAreaDisabled()) {
- // don't unhide
- return;
- }
-
- mSystemIconArea.setAlpha(1f);
- mSystemIconArea.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- public void onSystemChromeAnimationUpdate(@NonNull ValueAnimator animator) {
- mSystemIconArea.setAlpha((float) animator.getAnimatedValue());
+ public Animator onSystemEventAnimationFinish(boolean hasPersistentDot) {
+ return mSystemEventAnimator.onSystemEventAnimationFinish(hasPersistentDot);
}
private boolean isSystemIconAreaDisabled() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
new file mode 100644
index 0000000..f530ec8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.fragment
+
+import android.animation.Animator
+import android.animation.AnimatorSet
+import android.animation.ValueAnimator
+import android.content.res.Resources
+import android.view.View
+import com.android.systemui.R
+import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_IN
+import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_OUT
+import com.android.systemui.statusbar.events.SystemStatusAnimationCallback
+
+/**
+ * Tied directly to [SystemStatusAnimationScheduler]. Any StatusBar-like thing (keyguard, collapsed
+ * status bar fragment), can just feed this an animatable view to get the default system status
+ * animation.
+ *
+ * This animator relies on resources, and should be recreated whenever resources are updated. While
+ * this class could be used directly as the animation callback, it's probably best to forward calls
+ * to it so that it can be recreated at any moment without needing to remove/add callback.
+ */
+class StatusBarSystemEventAnimator(
+ val animatedView: View,
+ resources: Resources
+) : SystemStatusAnimationCallback {
+ private val translationXIn: Int = resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_chip_animation_in_status_bar_translation_x)
+ private val translationXOut: Int = resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_chip_animation_out_status_bar_translation_x)
+
+ override fun onSystemEventAnimationBegin(): Animator {
+ val moveOut = ValueAnimator.ofFloat(0f, 1f).setDuration(383)
+ moveOut.interpolator = STATUS_BAR_X_MOVE_OUT
+ moveOut.addUpdateListener { animation: ValueAnimator ->
+ animatedView.translationX = -(translationXIn * animation.animatedValue as Float)
+ }
+ val alphaOut = ValueAnimator.ofFloat(1f, 0f).setDuration(133)
+ alphaOut.interpolator = null
+ alphaOut.addUpdateListener { animation: ValueAnimator ->
+ animatedView.alpha = animation.animatedValue as Float
+ }
+
+ val animSet = AnimatorSet()
+ animSet.playTogether(moveOut, alphaOut)
+ return animSet
+ }
+
+ override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator {
+ animatedView.translationX = translationXOut.toFloat()
+ val moveIn = ValueAnimator.ofFloat(1f, 0f).setDuration(467)
+ moveIn.startDelay = 33
+ moveIn.interpolator = STATUS_BAR_X_MOVE_IN
+ moveIn.addUpdateListener { animation: ValueAnimator ->
+ animatedView.translationX = translationXOut * animation.animatedValue as Float
+ }
+ val alphaIn = ValueAnimator.ofFloat(0f, 1f).setDuration(167)
+ alphaIn.startDelay = 67
+ alphaIn.interpolator = null
+ alphaIn.addUpdateListener { animation: ValueAnimator ->
+ animatedView.alpha = animation.animatedValue as Float
+ }
+
+ val animatorSet = AnimatorSet()
+ animatorSet.playTogether(moveIn, alphaIn)
+
+ return animatorSet
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
index bd87875..f845101 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
@@ -299,10 +299,7 @@
view.clearAttachment()
entry.remoteInputUri = null
entry.remoteInputMimeType = null
- val resultSource = entry.editedSuggestionInfo
- ?.let { RemoteInput.SOURCE_FREE_FORM_INPUT }
- ?: RemoteInput.SOURCE_CHOICE
- RemoteInput.setResultsSource(fillInIntent, resultSource)
+ RemoteInput.setResultsSource(fillInIntent, remoteInputResultsSource)
return fillInIntent
}
@@ -332,10 +329,12 @@
entry.remoteInputText = fullText
// mirror prepareRemoteInputFromText for text input
- val resultSource = entry.editedSuggestionInfo
- ?.let { RemoteInput.SOURCE_FREE_FORM_INPUT }
- ?: RemoteInput.SOURCE_CHOICE
- RemoteInput.setResultsSource(fillInIntent, resultSource)
+ RemoteInput.setResultsSource(fillInIntent, remoteInputResultsSource)
return fillInIntent
}
+
+ private val remoteInputResultsSource
+ get() = entry.editedSuggestionInfo
+ ?.let { RemoteInput.SOURCE_CHOICE }
+ ?: RemoteInput.SOURCE_FREE_FORM_INPUT
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt b/packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt
new file mode 100644
index 0000000..c0538c1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.animation
+
+import kotlin.math.roundToLong
+
+/** A generic util class for animations in SysUI. */
+class AnimationUtil {
+ companion object {
+ /**
+ * Returns the number of milliseconds there are in [numFrames] for a 60 fps device.
+ *
+ * Note that this method can be used on any device, not just 60 fps devices. Animation
+ * lengths are typically specified in terms of number of frames for a 60 fps device, and
+ * the value "5 frames" is often more meaningful than "83ms". This method allows us to
+ * write animation code in terms of the more meaningful "5" number.
+ *
+ * @param numFrames must be >= 0.
+ */
+ fun getMsForFrames(numFrames: Int): Long {
+ if (numFrames < 0) {
+ throw IllegalArgumentException("numFrames must be >= 0")
+ }
+ return (numFrames * 1000f / 60f).roundToLong()
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 7a0db1f..8c79277 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -208,6 +208,11 @@
}
}
+ /** Delegates to {@link android.testing.TestableResources#addOverride(int, Object)}. */
+ protected void overrideResource(int resourceId, Object value) {
+ mContext.getOrCreateTestableResources().addOverride(resourceId, value);
+ }
+
public static final class EmptyRunnable implements Runnable {
public void run() {
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index a49c4d7..c684b66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -172,11 +172,10 @@
@Test
public void enableWindowMagnification_notifySourceBoundsChanged() {
- mInstrumentation.runOnMainSync(() -> {
- mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
- Float.NaN, /* magnificationFrameOffsetRatioX= */ 0,
- /* magnificationFrameOffsetRatioY= */ 0, null);
- });
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+ Float.NaN, /* magnificationFrameOffsetRatioX= */ 0,
+ /* magnificationFrameOffsetRatioY= */ 0, null));
// Waits for the surface created
verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS)).onSourceBoundsChanged(
@@ -184,6 +183,16 @@
}
@Test
+ public void enableWindowMagnification_disabled_notifySourceBoundsChanged() {
+ enableWindowMagnification_notifySourceBoundsChanged();
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.deleteWindowMagnification(null));
+ Mockito.reset(mWindowMagnifierCallback);
+
+ enableWindowMagnification_notifySourceBoundsChanged();
+ }
+
+ @Test
public void enableWindowMagnification_withAnimation_schedulesFrame() {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(2.0f, 10,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index ec2c1de..a95da62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -114,12 +114,13 @@
}
@Test
- fun testFingerprintTrigger_Ripple() {
+ fun testFingerprintTrigger_KeyguardVisible_Ripple() {
// GIVEN fp exists, keyguard is visible, user doesn't need strong auth
val fpsLocation = PointF(5f, 5f)
`when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
controller.onViewAttached()
`when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
+ `when`(keyguardUpdateMonitor.isDreaming).thenReturn(false)
`when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
// WHEN fingerprint authenticated
@@ -136,7 +137,30 @@
}
@Test
- fun testFingerprintTrigger_KeyguardNotVisible_NoRipple() {
+ fun testFingerprintTrigger_Dreaming_Ripple() {
+ // GIVEN fp exists, keyguard is visible, user doesn't need strong auth
+ val fpsLocation = PointF(5f, 5f)
+ `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
+ controller.onViewAttached()
+ `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
+ `when`(keyguardUpdateMonitor.isDreaming).thenReturn(true)
+ `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
+
+ // WHEN fingerprint authenticated
+ val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
+ verify(keyguardUpdateMonitor).registerCallback(captor.capture())
+ captor.value.onBiometricAuthenticated(
+ 0 /* userId */,
+ BiometricSourceType.FINGERPRINT /* type */,
+ false /* isStrongBiometric */)
+
+ // THEN update sensor location and show ripple
+ verify(rippleView).setFingerprintSensorLocation(fpsLocation, -1f)
+ verify(rippleView).startUnlockedRipple(any())
+ }
+
+ @Test
+ fun testFingerprintTrigger_KeyguardNotVisible_NotDreaming_NoRipple() {
// GIVEN fp exists & user doesn't need strong auth
val fpsLocation = PointF(5f, 5f)
`when`(authController.udfpsSensorLocation).thenReturn(fpsLocation)
@@ -145,6 +169,7 @@
// WHEN keyguard is NOT visible & fingerprint authenticated
`when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
+ `when`(keyguardUpdateMonitor.isDreaming).thenReturn(false)
val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
verify(keyguardUpdateMonitor).registerCallback(captor.capture())
captor.value.onBiometricAuthenticated(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
index daf81bd..dcbe0ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -37,6 +37,7 @@
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import javax.inject.Provider
+import org.mockito.Mockito.`when` as whenever
private val DATA = MediaData(
userId = -1,
@@ -82,6 +83,7 @@
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
+ whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
mediaCarouselController = MediaCarouselController(
context,
mediaControlPanelFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 90eff1a..cb68d81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -101,6 +101,7 @@
@Mock private lateinit var mediaOutputDialogFactory: MediaOutputDialogFactory
@Mock private lateinit var mediaCarouselController: MediaCarouselController
@Mock private lateinit var falsingManager: FalsingManager
+ @Mock private lateinit var mediaFlags: MediaFlags
private lateinit var appIcon: ImageView
private lateinit var albumView: ImageView
private lateinit var titleText: TextView
@@ -146,7 +147,7 @@
player = MediaControlPanel(context, bgExecutor, activityStarter, broadcastSender,
mediaViewController, seekBarViewModel, Lazy { mediaDataManager },
- mediaOutputDialogFactory, mediaCarouselController, falsingManager, clock)
+ mediaOutputDialogFactory, mediaCarouselController, falsingManager, mediaFlags, clock)
whenever(seekBarViewModel.progress).thenReturn(seekBarData)
// Set up mock views for the players
@@ -214,6 +215,9 @@
device = device,
active = true,
resumeAction = null)
+
+ whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(false)
+ whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
}
/**
@@ -291,6 +295,9 @@
@Test
fun bindSemanticActionsOldLayout() {
+ whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
+
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
val semanticActions = MediaButton(
playOrPause = MediaAction(icon, Runnable {}, "play"),
@@ -325,6 +332,9 @@
@Test
fun bindSemanticActionsNewLayout() {
+ whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
+
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
val semanticActions = MediaButton(
playOrPause = MediaAction(icon, Runnable {}, "play"),
@@ -371,6 +381,9 @@
@Test
fun bindNotificationActionsNewLayout() {
+ whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
+
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
val actions = listOf(
MediaAction(icon, Runnable {}, "previous"),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index be2450d..925ae30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -26,7 +26,6 @@
import com.android.systemui.statusbar.SbnBuilder
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
@@ -38,7 +37,6 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
@@ -169,7 +167,7 @@
whenever(mediaSmartspaceTarget.featureType).thenReturn(SmartspaceTarget.FEATURE_MEDIA)
whenever(mediaSmartspaceTarget.iconGrid).thenReturn(listOf(mediaRecommendationItem))
whenever(mediaSmartspaceTarget.creationTimeMillis).thenReturn(1234L)
- whenever(mediaFlags.areMediaSessionActionsEnabled(any(), anyInt())).thenReturn(false)
+ whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(false)
}
@After
@@ -596,7 +594,7 @@
@Test
fun testPlaybackActions_noState_usesNotification() {
val desc = "Notification Action"
- whenever(mediaFlags.areMediaSessionActionsEnabled(any(), anyInt())).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
whenever(controller.playbackState).thenReturn(null)
val notifWithAction = SbnBuilder().run {
@@ -623,7 +621,7 @@
@Test
fun testPlaybackActions_hasPrevNext() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4")
- whenever(mediaFlags.areMediaSessionActionsEnabled(any(), anyInt())).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY or
PlaybackState.ACTION_SKIP_TO_PREVIOUS or
PlaybackState.ACTION_SKIP_TO_NEXT
@@ -671,7 +669,7 @@
@Test
fun testPlaybackActions_noPrevNext_usesCustom() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4", "custom 5")
- whenever(mediaFlags.areMediaSessionActionsEnabled(any(), anyInt())).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY
val stateBuilder = PlaybackState.Builder()
.setActions(stateActions)
@@ -709,7 +707,7 @@
@Test
fun testPlaybackActions_reservedSpace() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4")
- whenever(mediaFlags.areMediaSessionActionsEnabled(any(), anyInt())).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY
val stateBuilder = PlaybackState.Builder()
.setActions(stateActions)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index 8e201b5..203eb47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -223,6 +223,18 @@
}
@Test
+ fun calculateTransformationType_onLockSplitShade_goingToFullShade_mediaInvisible_returnsFade() {
+ enableSplitShade()
+ goToLockscreen()
+ expandQS()
+ whenever(lockHost.visible).thenReturn(false)
+ mediaHiearchyManager.setTransitionToFullShadeAmount(10000f)
+
+ val transformType = mediaHiearchyManager.calculateTransformationType()
+ assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
+ }
+
+ @Test
fun calculateTransformationType_onLockShade_inSplitShade_notExpanding_returnsFade() {
enableSplitShade()
goToLockscreen()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
index ccce577..962d78c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
@@ -81,6 +81,9 @@
whenever(packageManager.getApplicationIcon(PACKAGE_NAME)).thenReturn(appIconFromPackageName)
whenever(applicationInfo.loadLabel(packageManager)).thenReturn(APP_NAME)
whenever(packageManager.getApplicationInfo(
+ any(), any<PackageManager.ApplicationInfoFlags>()
+ )).thenThrow(PackageManager.NameNotFoundException())
+ whenever(packageManager.getApplicationInfo(
eq(PACKAGE_NAME), any<PackageManager.ApplicationInfoFlags>()
)).thenReturn(applicationInfo)
context.setMockPackageManager(packageManager)
@@ -189,6 +192,28 @@
verify(windowManager, never()).removeView(any())
}
+
+ @Test
+ fun displayChip_nullAppIconDrawableAndNullPackageName_stillHasIcon() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(chipView, appPackageName = null, appIconDrawableOverride = null)
+
+ assertThat(chipView.getAppIconView().drawable).isNotNull()
+ }
+
+ @Test
+ fun displayChip_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(
+ chipView, appPackageName = "fakePackageName", appIconDrawableOverride = null
+ )
+
+ assertThat(chipView.getAppIconView().drawable).isNotNull()
+ }
@Test
fun setIcon_nullAppIconDrawable_iconIsFromPackageName() {
@@ -212,6 +237,28 @@
}
@Test
+ fun displayChip_nullAppNameAndNullPackageName_stillHasContentDescription() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(chipView, appPackageName = null, appNameOverride = null)
+
+ assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+ }
+
+ @Test
+ fun displayChip_nullAppNameAndInvalidPackageName_stillHasContentDescription() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(
+ chipView, appPackageName = "fakePackageName", appNameOverride = null
+ )
+
+ assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+ }
+
+ @Test
fun displayChip_nullAppName_iconContentDescriptionIsFromPackageName() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 64a0a23..1d2a0ca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.statusbar
+import org.mockito.Mockito.`when` as whenever
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -18,11 +19,11 @@
import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
import com.android.systemui.statusbar.phone.NotificationPanelViewController
import com.android.systemui.statusbar.phone.ScrimController
-import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.policy.FakeConfigurationController
import org.junit.After
import org.junit.Assert.assertFalse
@@ -37,14 +38,13 @@
import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
-import org.mockito.Mockito.`when` as whenever
-import org.mockito.ArgumentMatchers.eq
private fun <T> anyObject(): T {
return Mockito.anyObject<T>()
@@ -231,7 +231,7 @@
transitionController.dragDownAmount = 10f
verify(nsslController, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
verify(mediaHierarchyManager, never()).setTransitionToFullShadeAmount(anyFloat())
- verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat())
+ verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong())
verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
@@ -242,7 +242,7 @@
transitionController.dragDownAmount = 10f
verify(nsslController).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
verify(mediaHierarchyManager).setTransitionToFullShadeAmount(anyFloat())
- verify(scrimController).setTransitionToFullShadeProgress(anyFloat())
+ verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong())
verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
@@ -311,6 +311,75 @@
}
@Test
+ fun setDragAmount_setsScrimProgressBasedOnScrimDistance() {
+ val distance = 10
+ context.orCreateTestableResources
+ .addOverride(R.dimen.lockscreen_shade_scrim_transition_distance, distance)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 5f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = eq(0.5f),
+ lockScreenNotificationsProgress = anyFloat()
+ )
+ }
+
+ @Test
+ fun setDragAmount_setsNotificationsScrimProgressBasedOnNotificationsScrimDistanceAndDelay() {
+ val distance = 100
+ val delay = 10
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 20f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = anyFloat(),
+ lockScreenNotificationsProgress = eq(0.1f)
+ )
+ }
+
+ @Test
+ fun setDragAmount_dragAmountLessThanNotifDelayDistance_setsNotificationsScrimProgressToZero() {
+ val distance = 100
+ val delay = 50
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 20f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = anyFloat(),
+ lockScreenNotificationsProgress = eq(0f)
+ )
+ }
+
+ @Test
+ fun setDragAmount_dragAmountMoreThanTotalDistance_setsNotificationsScrimProgressToOne() {
+ val distance = 100
+ val delay = 50
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 999999f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = anyFloat(),
+ lockScreenNotificationsProgress = eq(1f)
+ )
+ }
+
+ @Test
fun setDragDownAmount_inSplitShade_setsValueOnMediaHierarchyManager() {
enableSplitShade()
@@ -328,9 +397,21 @@
}
private fun setSplitShadeEnabled(enabled: Boolean) {
- context.getOrCreateTestableResources().addOverride(
- R.bool.config_use_split_notification_shade, enabled
- )
+ overrideResource(R.bool.config_use_split_notification_shade, enabled)
configurationController.notifyConfigurationChanged()
}
+
+ /**
+ * Wrapper around [ScrimController.transitionToFullShadeProgress] that has named parameters for
+ * clarify and easier refactoring of parameter names.
+ */
+ private fun ScrimController.transitionToFullShadeProgress(
+ progress: Float,
+ lockScreenNotificationsProgress: Float
+ ) {
+ scrimController.setTransitionToFullShadeProgress(
+ progress,
+ lockScreenNotificationsProgress
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 7fc5ece..251ac7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -41,6 +41,7 @@
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.R;
@@ -87,6 +88,7 @@
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.SmartReplyStateInflater;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -252,13 +254,17 @@
.thenAnswer((Answer<ExpandableNotificationRowController>) invocation ->
new ExpandableNotificationRowController(
viewCaptor.getValue(),
- mListContainer,
- mock(RemoteInputViewSubcomponent.Factory.class),
mock(ActivatableNotificationViewController.class),
+ mock(RemoteInputViewSubcomponent.Factory.class),
+ mock(MetricsLogger.class),
+ mListContainer,
mNotificationMediaManager,
+ mock(SmartReplyConstants.class),
+ mock(SmartReplyController.class),
mock(PluginManager.class),
new FakeSystemClock(),
- "FOOBAR", "FOOBAR",
+ "FOOBAR",
+ "FOOBAR",
mKeyguardBypassController,
mGroupMembershipManager,
mGroupExpansionManager,
@@ -275,8 +281,7 @@
mock(FeatureFlags.class),
mPeopleNotificationIdentifier,
Optional.of(mock(BubblesManager.class)),
- mock(ExpandableNotificationRowDragController.class)
- ));
+ mock(ExpandableNotificationRowDragController.class)));
when(mNotificationRowComponentBuilder.activatableNotificationView(any()))
.thenReturn(mNotificationRowComponentBuilder);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 72f8f70..1ecb09b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -44,6 +44,7 @@
import android.view.LayoutInflater;
import android.widget.RemoteViews;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.TestableDependency;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
@@ -54,6 +55,7 @@
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -73,6 +75,7 @@
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.SmartReplyStateInflater;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.tests.R;
@@ -505,7 +508,10 @@
mPeopleNotificationIdentifier,
mOnUserInteractionCallback,
Optional.of(mock(BubblesManager.class)),
- mock(NotificationGutsManager.class));
+ mock(NotificationGutsManager.class),
+ mock(MetricsLogger.class),
+ mock(SmartReplyConstants.class),
+ mock(SmartReplyController.class));
row.setAboveShelfChangedListener(aboveShelf -> { });
mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
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 eafcc35..56541f3 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
@@ -161,17 +161,6 @@
}
@Test
- public void testUpdateStackEndHeight_forEndOfStackHeightAnimation() {
- final float nsslHeight = 10f;
- final float bottomMargin = 1f;
- final float topPadding = 1f;
-
- mStackScroller.updateStackEndHeight(nsslHeight, bottomMargin, topPadding);
- final float stackEndHeight = nsslHeight - bottomMargin - topPadding;
- assertTrue(mAmbientState.getStackEndHeight() == stackEndHeight);
- }
-
- @Test
public void testUpdateStackHeight_withDozeAmount_whenDozeChanging() {
final float dozeAmount = 0.5f;
mAmbientState.setDozeAmount(dozeAmount);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
index 83eabb6..6526fab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
@@ -6,7 +6,6 @@
import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowManagerPolicyConstants
-import androidx.annotation.AnyRes
import androidx.annotation.IdRes
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
@@ -104,10 +103,6 @@
windowInsetsCallback = windowInsetsCallbackCaptor.value
}
- private fun overrideResource(@AnyRes id: Int, value: Any) {
- mContext.orCreateTestableResources.addOverride(id, value)
- }
-
@Test
fun testTaskbarVisibleInSplitShade() {
enableSplitShade()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 0b25467..786a858 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.statusbar.phone.ScrimController.KEYGUARD_SCRIM_ALPHA;
import static com.android.systemui.statusbar.phone.ScrimController.OPAQUE;
import static com.android.systemui.statusbar.phone.ScrimController.SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.ScrimController.TRANSPARENT;
@@ -1263,19 +1262,36 @@
mScrimController.setClipsQsScrim(true);
float progress = 0.5f;
- mScrimController.setTransitionToFullShadeProgress(progress);
+ float lsNotifProgress = 0.3f;
+ mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
mNotificationsScrim.getViewAlpha(), 0.2);
progress = 0.0f;
- mScrimController.setTransitionToFullShadeProgress(progress);
+ mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
mNotificationsScrim.getViewAlpha(), 0.2);
progress = 1.0f;
- mScrimController.setTransitionToFullShadeProgress(progress);
+ mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
mNotificationsScrim.getViewAlpha(), 0.2);
}
+ @Test
+ public void notificationTransparency_followsNotificationScrimProgress() {
+ mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+ mScrimController.setRawPanelExpansionFraction(1.0f);
+ finishAnimationsImmediately();
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ mScrimController.setRawPanelExpansionFraction(1.0f);
+ finishAnimationsImmediately();
+
+ float progress = 0.5f;
+ float notifProgress = 0.3f;
+ mScrimController.setTransitionToFullShadeProgress(progress, notifProgress);
+
+ assertThat(mNotificationsScrim.getViewAlpha()).isEqualTo(notifProgress);
+ }
+
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
mScrimController.setRawPanelExpansionFraction(expansion);
finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index d48ce8c..fa867e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -447,4 +447,15 @@
controllerCaptor.getValue().onIntentStarted(false);
verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
}
+
+ @Test
+ public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse_noAnimate() {
+ NotifActivityLaunchEvents.Listener listener =
+ mock(NotifActivityLaunchEvents.Listener.class);
+ mLaunchEventsEmitter.registerListener(listener);
+ when(mCentralSurfaces.shouldAnimateLaunch(anyBoolean())).thenReturn(false);
+ mNotificationActivityStarter
+ .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
+ verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
new file mode 100644
index 0000000..92afb03
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.animation
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import java.lang.IllegalArgumentException
+
+@SmallTest
+class AnimationUtilTest : SysuiTestCase() {
+ @Test
+ fun getMsForFrames_5frames_returns83() {
+ assertThat(AnimationUtil.getMsForFrames(5)).isEqualTo(83L)
+ }
+
+ @Test
+ fun getMsForFrames_7frames_returns117() {
+ assertThat(AnimationUtil.getMsForFrames(7)).isEqualTo(117L)
+ }
+
+ @Test
+ fun getMsForFrames_30frames_returns500() {
+ assertThat(AnimationUtil.getMsForFrames(30)).isEqualTo(500L)
+ }
+
+ @Test
+ fun getMsForFrames_60frames_returns1000() {
+ assertThat(AnimationUtil.getMsForFrames(60)).isEqualTo(1000L)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun getMsForFrames_negativeFrames_throwsException() {
+ AnimationUtil.getMsForFrames(-1)
+ }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index fa32452..ecc45eb 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -18,6 +18,7 @@
import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_FULLSCREEN;
+import static android.util.TypedValue.COMPLEX_UNIT_DIP;
import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
import static com.android.server.accessibility.AccessibilityManagerService.INVALID_SERVICE_ID;
@@ -31,15 +32,20 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.CompatibilityInfo;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.display.DisplayManagerInternal;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
import android.util.MathUtils;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TypedValue;
import android.view.Display;
+import android.view.DisplayInfo;
import android.view.MagnificationSpec;
import android.view.View;
import android.view.accessibility.MagnificationAnimationCallback;
@@ -93,6 +99,8 @@
// Whether the following typing focus feature for magnification is enabled.
private boolean mMagnificationFollowTypingEnabled = true;
+ private final DisplayManagerInternal mDisplayManagerInternal;
+
/**
* This class implements {@link WindowManagerInternal.MagnificationCallbacks} and holds
* magnification information per display.
@@ -395,6 +403,18 @@
outRegion.set(mMagnificationRegion);
}
+ private DisplayMetrics getDisplayMetricsForId() {
+ final DisplayMetrics outMetrics = new DisplayMetrics();
+ final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
+ if (displayInfo != null) {
+ displayInfo.getLogicalMetrics(outMetrics,
+ CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+ } else {
+ outMetrics.setToDefaults();
+ }
+ return outMetrics;
+ }
+
void requestRectangleOnScreen(int left, int top, int right, int bottom) {
synchronized (mLock) {
final Rect magnifiedFrame = mTempRect;
@@ -408,6 +428,12 @@
final float scrollX;
final float scrollY;
+ // We offset an additional distance for a user to know the surrounding context.
+ DisplayMetrics metrics = getDisplayMetricsForId();
+ final float offsetViewportX = (float) magnifFrameInScreenCoords.width() / 4;
+ final float offsetViewportY =
+ TypedValue.applyDimension(COMPLEX_UNIT_DIP, 10, metrics);
+
if (right - left > magnifFrameInScreenCoords.width()) {
final int direction = TextUtils
.getLayoutDirectionFromLocale(Locale.getDefault());
@@ -417,9 +443,9 @@
scrollX = right - magnifFrameInScreenCoords.right;
}
} else if (left < magnifFrameInScreenCoords.left) {
- scrollX = left - magnifFrameInScreenCoords.left;
+ scrollX = left - magnifFrameInScreenCoords.left - offsetViewportX;
} else if (right > magnifFrameInScreenCoords.right) {
- scrollX = right - magnifFrameInScreenCoords.right;
+ scrollX = right - magnifFrameInScreenCoords.right + offsetViewportX;
} else {
scrollX = 0;
}
@@ -427,9 +453,9 @@
if (bottom - top > magnifFrameInScreenCoords.height()) {
scrollY = top - magnifFrameInScreenCoords.top;
} else if (top < magnifFrameInScreenCoords.top) {
- scrollY = top - magnifFrameInScreenCoords.top;
+ scrollY = top - magnifFrameInScreenCoords.top - offsetViewportY;
} else if (bottom > magnifFrameInScreenCoords.bottom) {
- scrollY = bottom - magnifFrameInScreenCoords.bottom;
+ scrollY = bottom - magnifFrameInScreenCoords.bottom + offsetViewportY;
} else {
scrollY = 0;
}
@@ -687,6 +713,7 @@
mScreenStateObserver = new ScreenStateObserver(mControllerCtx.getContext(), this);
mMagnificationInfoChangedCallback = magnificationInfoChangedCallback;
mScaleProvider = scaleProvider;
+ mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
}
/**
diff --git a/services/api/current.txt b/services/api/current.txt
index 5a28802..780fccf 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -47,6 +47,9 @@
package com.android.server.pm {
public interface PackageManagerLocal {
+ method public void reconcileSdkData(@Nullable String, @NonNull String, @NonNull java.util.List<java.lang.String>, int, int, int, @NonNull String, int) throws java.io.IOException;
+ field public static final int FLAG_STORAGE_CE = 2; // 0x2
+ field public static final int FLAG_STORAGE_DE = 1; // 0x1
}
}
diff --git a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
index 116c739..8e0e395 100644
--- a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
+++ b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
@@ -107,6 +107,10 @@
@GuardedBy("mLock")
public void onSearchLocked(@NonNull SearchRequest searchRequest,
@NonNull ICloudSearchManagerCallback callback) {
+ if (mRemoteComponentName == null) {
+ return;
+ }
+
String filterList = searchRequest.getSearchConstraints().containsKey(
SearchRequest.CONSTRAINT_SEARCH_PROVIDER_FILTER)
? searchRequest.getSearchConstraints().getString(
diff --git a/services/companion/java/com/android/server/companion/CompanionApplicationController.java b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
index f32eebc..2a83a3c 100644
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
@@ -49,7 +49,7 @@
* The following is the list of the APIs provided by {@link CompanionApplicationController} (to be
* utilized by {@link CompanionDeviceManagerService}):
* <ul>
- * <li> {@link #bindCompanionApplication(int, String)}
+ * <li> {@link #bindCompanionApplication(int, String, boolean)}
* <li> {@link #unbindCompanionApplication(int, String)}
* <li> {@link #notifyCompanionApplicationDeviceAppeared(AssociationInfo)}
* <li> {@link #notifyCompanionApplicationDeviceDisappeared(AssociationInfo)}
@@ -103,8 +103,12 @@
mCompanionServicesRegister.invalidate(userId);
}
- void bindCompanionApplication(@UserIdInt int userId, @NonNull String packageName) {
- if (DEBUG) Log.i(TAG, "bind() u" + userId + "/" + packageName);
+ void bindCompanionApplication(@UserIdInt int userId, @NonNull String packageName,
+ boolean bindImportant) {
+ if (DEBUG) {
+ Log.i(TAG, "bind() u" + userId + "/" + packageName
+ + " important=" + bindImportant);
+ }
final List<ComponentName> companionServices =
mCompanionServicesRegister.forPackage(userId, packageName);
@@ -125,7 +129,8 @@
}
serviceConnectors = CollectionUtils.map(companionServices, componentName ->
- new CompanionDeviceServiceConnector(mContext, userId, componentName));
+ CompanionDeviceServiceConnector.newInstance(mContext, userId,
+ componentName, bindImportant));
mBoundCompanionApplications.setValueForPackage(userId, packageName, serviceConnectors);
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index eaa99f7..13a5a28 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -254,9 +254,12 @@
final int userId = association.getUserId();
final String packageName = association.getPackageName();
+ // Set bindImportant to true when the association is self-managed to avoid the target
+ // service being killed.
+ final boolean bindImportant = association.isSelfManaged();
if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
- mCompanionAppController.bindCompanionApplication(userId, packageName);
+ mCompanionAppController.bindCompanionApplication(userId, packageName, bindImportant);
} else if (DEBUG) {
Log.i(TAG, "u" + userId + "\\" + packageName + " is already bound");
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
index f2a58b7..4c7b9b8 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
@@ -16,6 +16,7 @@
package com.android.server.companion;
+import static android.content.Context.BIND_ALMOST_PERCEPTIBLE;
import static android.content.Context.BIND_IMPORTANT;
import static android.os.Process.THREAD_PRIORITY_DEFAULT;
@@ -44,20 +45,43 @@
class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDeviceService> {
private static final String TAG = "CompanionDevice_ServiceConnector";
private static final boolean DEBUG = false;
- private static final int BINDING_FLAGS = BIND_IMPORTANT;
/** Listener for changes to the state of the {@link CompanionDeviceServiceConnector} */
interface Listener {
void onBindingDied(@UserIdInt int userId, @NonNull String packageName);
}
- private final @UserIdInt int mUserId;
- private final @NonNull ComponentName mComponentName;
- private @Nullable Listener mListener;
+ @UserIdInt
+ private final int mUserId;
+ @NonNull
+ private final ComponentName mComponentName;
+ @Nullable
+ private Listener mListener;
- CompanionDeviceServiceConnector(@NonNull Context context, @UserIdInt int userId,
- @NonNull ComponentName componentName) {
- super(context, buildIntent(componentName), BINDING_FLAGS, userId, null);
+ /**
+ * Create a CompanionDeviceServiceConnector instance.
+ *
+ * When bindImportant is false, the binding flag will be BIND_ALMOST_PERCEPTIBLE
+ * (oom_score_adj = PERCEPTIBLE_MEDIUM_APP = 225). The target service will be treated
+ * as important as a perceptible app (IMPORTANCE_VISIBLE = 200), and will be unbound when
+ * the app is removed from task manager.
+ * When bindImportant is true, the binding flag will be BIND_IMPORTANT
+ * (oom_score_adj = PERCEPTIBLE_MEDIUM_APP = -700). The target service will
+ * have the highest priority to avoid being killed (IMPORTANCE_FOREGROUND = 100).
+ *
+ * One time permission's importance level to keep session alive is
+ * IMPORTANCE_FOREGROUND_SERVICE = 125. In order to kill the one time permission session, the
+ * service importance level should be higher than 125.
+ */
+ static CompanionDeviceServiceConnector newInstance(@NonNull Context context,
+ @UserIdInt int userId, @NonNull ComponentName componentName, boolean bindImportant) {
+ final int bindingFlags = bindImportant ? BIND_IMPORTANT : BIND_ALMOST_PERCEPTIBLE;
+ return new CompanionDeviceServiceConnector(context, userId, componentName, bindingFlags);
+ }
+
+ private CompanionDeviceServiceConnector(@NonNull Context context, @UserIdInt int userId,
+ @NonNull ComponentName componentName, int bindingFlags) {
+ super(context, buildIntent(componentName), bindingFlags, userId, null);
mUserId = userId;
mComponentName = componentName;
}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 569d480..2dfe947 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -1302,7 +1302,7 @@
pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
pw.print(" mNightMode="); pw.print(mNightMode); pw.print(" (");
- pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") ");
+ pw.print(Shell.nightModeToStr(mNightMode, mNightModeCustomType)); pw.print(") ");
pw.print(" mOverrideOn/Off="); pw.print(mOverrideNightModeOn);
pw.print("/"); pw.print(mOverrideNightModeOff);
@@ -1917,7 +1917,8 @@
public static final String NIGHT_MODE_STR_YES = "yes";
public static final String NIGHT_MODE_STR_NO = "no";
public static final String NIGHT_MODE_STR_AUTO = "auto";
- public static final String NIGHT_MODE_STR_CUSTOM = "custom";
+ public static final String NIGHT_MODE_STR_CUSTOM_SCHEDULE = "custom_schedule";
+ public static final String NIGHT_MODE_STR_CUSTOM_BEDTIME = "custom_bedtime";
public static final String NIGHT_MODE_STR_UNKNOWN = "unknown";
private final IUiModeManager mInterface;
@@ -1931,7 +1932,7 @@
pw.println("UiModeManager service (uimode) commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" night [yes|no|auto|custom]");
+ pw.println(" night [yes|no|auto|custom_schedule|custom_bedtime]");
pw.println(" Set or read night mode.");
pw.println(" car [yes|no]");
pw.println(" Set or read car mode.");
@@ -2001,14 +2002,19 @@
}
final int mode = strToNightMode(modeStr);
+ final int customType = strToNightModeCustomType(modeStr);
if (mode >= 0) {
mInterface.setNightMode(mode);
+ if (mode == UiModeManager.MODE_NIGHT_CUSTOM) {
+ mInterface.setNightModeCustomType(customType);
+ }
printCurrentNightMode();
return 0;
} else {
err.println("Error: mode must be '" + NIGHT_MODE_STR_YES + "', '"
+ NIGHT_MODE_STR_NO + "', or '" + NIGHT_MODE_STR_AUTO
- + "', or '" + NIGHT_MODE_STR_CUSTOM + "'");
+ + "', or '" + NIGHT_MODE_STR_CUSTOM_SCHEDULE + "', or '"
+ + NIGHT_MODE_STR_CUSTOM_BEDTIME + "'");
return -1;
}
}
@@ -2016,11 +2022,12 @@
private void printCurrentNightMode() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final int currMode = mInterface.getNightMode();
- final String currModeStr = nightModeToStr(currMode);
+ final int customType = mInterface.getNightModeCustomType();
+ final String currModeStr = nightModeToStr(currMode, customType);
pw.println("Night mode: " + currModeStr);
}
- private static String nightModeToStr(int mode) {
+ private static String nightModeToStr(int mode, int customType) {
switch (mode) {
case UiModeManager.MODE_NIGHT_YES:
return NIGHT_MODE_STR_YES;
@@ -2029,7 +2036,12 @@
case UiModeManager.MODE_NIGHT_AUTO:
return NIGHT_MODE_STR_AUTO;
case MODE_NIGHT_CUSTOM:
- return NIGHT_MODE_STR_CUSTOM;
+ if (customType == UiModeManager.MODE_NIGHT_CUSTOM_TYPE_SCHEDULE) {
+ return NIGHT_MODE_STR_CUSTOM_SCHEDULE;
+ }
+ if (customType == UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME) {
+ return NIGHT_MODE_STR_CUSTOM_BEDTIME;
+ }
default:
return NIGHT_MODE_STR_UNKNOWN;
}
@@ -2043,13 +2055,25 @@
return UiModeManager.MODE_NIGHT_NO;
case NIGHT_MODE_STR_AUTO:
return UiModeManager.MODE_NIGHT_AUTO;
- case NIGHT_MODE_STR_CUSTOM:
+ case NIGHT_MODE_STR_CUSTOM_SCHEDULE:
+ case NIGHT_MODE_STR_CUSTOM_BEDTIME:
return UiModeManager.MODE_NIGHT_CUSTOM;
default:
return -1;
}
}
+ private static int strToNightModeCustomType(String customTypeStr) {
+ switch (customTypeStr) {
+ case NIGHT_MODE_STR_CUSTOM_BEDTIME:
+ return UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME;
+ case NIGHT_MODE_STR_CUSTOM_SCHEDULE:
+ return UiModeManager.MODE_NIGHT_CUSTOM_TYPE_SCHEDULE;
+ default:
+ return -1;
+ }
+ }
+
private int handleCarMode() throws RemoteException {
final PrintWriter err = getErrPrintWriter();
final String modeStr = getNextArg();
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 48e3264..b0ab53907 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3801,6 +3801,18 @@
@GuardedBy("mAm")
void performScheduleRestartLocked(ServiceRecord r, @NonNull String scheduling,
@NonNull String reason, @UptimeMillisLong long now) {
+
+ // If the service is waiting to become a foreground service, remove the pending
+ // SERVICE_FOREGROUND_TIMEOUT_MSG msg, and set fgWaiting to false, so next time the service
+ // is brought up, scheduleServiceForegroundTransitionTimeoutLocked() can be called again and
+ // a new SERVICE_FOREGROUND_TIMEOUT_MSG is scheduled in SERVICE_START_FOREGROUND_TIMEOUT
+ // again.
+ if (r.fgRequired && r.fgWaiting) {
+ mAm.mHandler.removeMessages(
+ ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
+ r.fgWaiting = false;
+ }
+
mAm.mHandler.removeCallbacks(r.restarter);
mAm.mHandler.postAtTime(r.restarter, r.nextRestartTime);
r.nextRestartTime = now + r.restartDelay;
@@ -5678,7 +5690,7 @@
void serviceForegroundTimeout(ServiceRecord r) {
ProcessRecord app;
synchronized (mAm) {
- if (!r.fgRequired || r.destroying) {
+ if (!r.fgRequired || !r.fgWaiting || r.destroying) {
return;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0735648..9d9ee8c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2911,12 +2911,35 @@
return mAtmInternal.compatibilityInfoForPackage(ai);
}
+ /**
+ * Enforces that the uid that calls a method is not an
+ * {@link UserHandle#isIsolated(int) isolated} uid.
+ *
+ * @param caller the name of the method being called.
+ * @throws SecurityException if the calling uid is an isolated uid.
+ */
/* package */ void enforceNotIsolatedCaller(String caller) {
if (UserHandle.isIsolated(Binder.getCallingUid())) {
throw new SecurityException("Isolated process not allowed to call " + caller);
}
}
+ /**
+ * Enforces that the uid that calls a method is not an
+ * {@link UserHandle#isIsolated(int) isolated} uid or an
+ * {@link Process#isSdkSandboxUid(int) SDK sandbox} uid.
+ *
+ * @param caller the name of the method being called.
+ * @throws SecurityException if the calling uid is an isolated uid or SDK sandbox uid.
+ */
+ void enforceNotIsolatedOrSdkSandboxCaller(String caller) {
+ enforceNotIsolatedCaller(caller);
+
+ if (Process.isSdkSandboxUid(Binder.getCallingUid())) {
+ throw new SecurityException("SDK sandbox process not allowed to call " + caller);
+ }
+ }
+
@Override
public void setPackageScreenCompatMode(String packageName, int mode) {
mActivityTaskManager.setPackageScreenCompatMode(packageName, mode);
@@ -12843,7 +12866,7 @@
public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
String callerFeatureId, String receiverId, IIntentReceiver receiver,
IntentFilter filter, String permission, int userId, int flags) {
- enforceNotIsolatedCaller("registerReceiver");
+ enforceNotIsolatedOrSdkSandboxCaller("registerReceiver");
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
final boolean visibleToInstantApps
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 1131fa8..4fdc88d 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -561,8 +561,18 @@
// We were asked to fetch Bluetooth data.
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
- bluetoothReceiver = new SynchronousResultReceiver("bluetooth");
- adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+ SynchronousResultReceiver resultReceiver =
+ new SynchronousResultReceiver("bluetooth");
+ adapter.requestControllerActivityEnergyInfo(
+ Runnable::run,
+ info -> {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY,
+ info);
+ resultReceiver.send(0, bundle);
+ }
+ );
+ bluetoothReceiver = resultReceiver;
}
}
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
index b73cf5b..42a7423 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
@@ -171,16 +171,15 @@
return;
}
- // Remove any existing intent and unregister for this package before adding a new one.
+ // Remove any existing PendingIntent for this package.
String callingPackage = pendingIntent.getCreatorPackage();
PendingIntent duplicatePendingIntent = findExistingRequestByPackage(callingPackage);
if (duplicatePendingIntent != null) {
- Slog.d(TAG, "Unregister duplicate request from " + callingPackage);
- onUnregisterObserver(callingPackage);
+ Slog.d(TAG, "Replace duplicate request from " + callingPackage);
mExistingPendingIntents.remove(duplicatePendingIntent);
}
- // Register new package and add request to mExistingRequests
+ // Register package and add pendingIntent to mExistingPendingIntents
startDetection(request, callingPackage, createDetectionResultRemoteCallback(),
getServerStatusCallback(clientStatusCallback));
mExistingPendingIntents.add(pendingIntent);
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
index 010bf1b..e2b22dc 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
@@ -110,6 +110,8 @@
return runStopDetection();
case "get-last-status-code":
return getLastStatusCode();
+ case "get-last-package-name":
+ return getLastPackageName();
case "query-service-status":
return runQueryServiceStatus();
case "get-bound-package":
@@ -157,6 +159,13 @@
return lastResponse.getStatusCode();
}
+ private int getLastPackageName() {
+ AmbientContextDetectionServiceStatus lastResponse =
+ sTestableCallbackInternal.getLastStatus();
+ out.println(lastResponse == null ? "" : lastResponse.getPackageName());
+ return 0;
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -167,6 +176,7 @@
pw.println(" start-detection USER_ID PACKAGE_NAME: Starts AmbientContextEvent detection.");
pw.println(" stop-detection USER_ID: Stops AmbientContextEvent detection.");
pw.println(" get-last-status-code: Prints the latest request status code.");
+ pw.println(" get-last-package-name: Prints the latest request package name.");
pw.println(" query-event-status USER_ID PACKAGE_NAME: Prints the event status code.");
pw.println(" get-bound-package USER_ID:"
+ " Print the bound package that implements the service.");
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d01be58..309a4ff 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -102,6 +102,7 @@
import android.media.IRingtonePlayer;
import android.media.ISpatializerCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback;
+import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerOutputCallback;
import android.media.IStrategyPreferredDevicesDispatcher;
@@ -8723,6 +8724,11 @@
return mSpatializerHelper.isHeadTrackerEnabled(Objects.requireNonNull(device));
}
+ /** @see Spatializer#isHeadTrackerAvailable() */
+ public boolean isHeadTrackerAvailable() {
+ return mSpatializerHelper.isHeadTrackerAvailable();
+ }
+
/** @see Spatializer#setSpatializerEnabled(boolean) */
public void setSpatializerEnabled(boolean enabled) {
enforceModifyDefaultAudioEffectsPermission();
@@ -8767,6 +8773,13 @@
mSpatializerHelper.unregisterHeadTrackingModeCallback(cb);
}
+ /** @see Spatializer.SpatializerHeadTrackerAvailableDispatcherStub */
+ public void registerSpatializerHeadTrackerAvailableCallback(
+ @NonNull ISpatializerHeadTrackerAvailableCallback cb, boolean register) {
+ Objects.requireNonNull(cb);
+ mSpatializerHelper.registerHeadTrackerAvailableCallback(cb, register);
+ }
+
/** @see Spatializer#setOnHeadToSoundstagePoseUpdatedListener */
public void registerHeadToSoundstagePoseCallback(
@NonNull ISpatializerHeadToSoundStagePoseCallback cb) {
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 5af73c9..f0f04e2 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -30,6 +30,7 @@
import android.media.ISpatializer;
import android.media.ISpatializerCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback;
+import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingCallback;
import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerOutputCallback;
@@ -126,6 +127,7 @@
private boolean mBinauralSupported = false;
private int mActualHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
private int mDesiredHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD;
+ private boolean mHeadTrackerAvailable = false;
/**
* The desired head tracking mode when enabling head tracking, tracks mDesiredHeadTrackingMode,
* except when head tracking gets disabled through setting the desired mode to
@@ -137,6 +139,7 @@
private @Nullable SpatializerCallback mSpatCallback;
private @Nullable SpatializerHeadTrackingCallback mSpatHeadTrackingCallback;
private @Nullable HelperDynamicSensorCallback mDynSensorCallback;
+ private boolean mIsHeadTrackingSupported = false;
// default attributes and format that determine basic availability of spatialization
private static final AudioAttributes DEFAULT_ATTRIBUTES = new AudioAttributes.Builder()
@@ -811,8 +814,9 @@
mSpat = AudioSystem.getSpatializer(mSpatCallback);
try {
mSpat.setLevel((byte) Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL);
+ mIsHeadTrackingSupported = mSpat.isHeadTrackingSupported();
//TODO: register heatracking callback only when sensors are registered
- if (mSpat.isHeadTrackingSupported()) {
+ if (mIsHeadTrackingSupported) {
mSpat.registerHeadTrackingCallback(mSpatHeadTrackingCallback);
}
} catch (RemoteException e) {
@@ -830,11 +834,15 @@
if (mSpat != null) {
mSpatCallback = null;
try {
- mSpat.registerHeadTrackingCallback(null);
+ if (mIsHeadTrackingSupported) {
+ mSpat.registerHeadTrackingCallback(null);
+ }
+ mHeadTrackerAvailable = false;
mSpat.release();
} catch (RemoteException e) {
Log.e(TAG, "Can't set release spatializer cleanly", e);
}
+ mIsHeadTrackingSupported = false;
mSpat = null;
}
}
@@ -890,6 +898,18 @@
mHeadTrackingModeCallbacks.unregister(callback);
}
+ final RemoteCallbackList<ISpatializerHeadTrackerAvailableCallback> mHeadTrackerCallbacks =
+ new RemoteCallbackList<>();
+
+ synchronized void registerHeadTrackerAvailableCallback(
+ @NonNull ISpatializerHeadTrackerAvailableCallback cb, boolean register) {
+ if (register) {
+ mHeadTrackerCallbacks.register(cb);
+ } else {
+ mHeadTrackerCallbacks.unregister(cb);
+ }
+ }
+
synchronized int[] getSupportedHeadTrackingModes() {
switch (mState) {
case STATE_UNINITIALIZED:
@@ -1090,6 +1110,10 @@
return false;
}
+ synchronized boolean isHeadTrackerAvailable() {
+ return mHeadTrackerAvailable;
+ }
+
private boolean checkSpatForHeadTracking(String funcName) {
switch (mState) {
case STATE_UNINITIALIZED:
@@ -1105,7 +1129,7 @@
}
break;
}
- return true;
+ return mIsHeadTrackingSupported;
}
private void dispatchActualHeadTrackingMode(int newMode) {
@@ -1115,7 +1139,8 @@
mHeadTrackingModeCallbacks.getBroadcastItem(i)
.dispatchSpatializerActualHeadTrackingModeChanged(newMode);
} catch (RemoteException e) {
- Log.e(TAG, "Error in dispatchSpatializerActualHeadTrackingModeChanged", e);
+ Log.e(TAG, "Error in dispatchSpatializerActualHeadTrackingModeChanged("
+ + newMode + ")", e);
}
}
mHeadTrackingModeCallbacks.finishBroadcast();
@@ -1128,12 +1153,27 @@
mHeadTrackingModeCallbacks.getBroadcastItem(i)
.dispatchSpatializerDesiredHeadTrackingModeChanged(newMode);
} catch (RemoteException e) {
- Log.e(TAG, "Error in dispatchSpatializerDesiredHeadTrackingModeChanged", e);
+ Log.e(TAG, "Error in dispatchSpatializerDesiredHeadTrackingModeChanged("
+ + newMode + ")", e);
}
}
mHeadTrackingModeCallbacks.finishBroadcast();
}
+ private void dispatchHeadTrackerAvailable(boolean available) {
+ final int nbCallbacks = mHeadTrackerCallbacks.beginBroadcast();
+ for (int i = 0; i < nbCallbacks; i++) {
+ try {
+ mHeadTrackerCallbacks.getBroadcastItem(i)
+ .dispatchSpatializerHeadTrackerAvailable(available);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in dispatchSpatializerHeadTrackerAvailable("
+ + available + ")", e);
+ }
+ }
+ mHeadTrackerCallbacks.finishBroadcast();
+ }
+
//------------------------------------------------------
// head pose
final RemoteCallbackList<ISpatializerHeadToSoundStagePoseCallback> mHeadPoseCallbacks =
@@ -1279,13 +1319,8 @@
Log.e(TAG, "not " + action + " sensors, null spatializer");
return;
}
- try {
- if (!mSpat.isHeadTrackingSupported()) {
- Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
- return;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "not " + action + " sensors, error querying headtracking", e);
+ if (!mIsHeadTrackingSupported) {
+ Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
return;
}
int headHandle = -1;
@@ -1348,6 +1383,10 @@
try {
Log.i(TAG, "setHeadSensor:" + headHandle);
mSpat.setHeadSensor(headHandle);
+ if (mHeadTrackerAvailable != (headHandle != -1)) {
+ mHeadTrackerAvailable = (headHandle != -1);
+ dispatchHeadTrackerAvailable(mHeadTrackerAvailable);
+ }
} catch (Exception e) {
Log.e(TAG, "Error calling setHeadSensor:" + headHandle, e);
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index fadcce9..954b930 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -20,6 +20,7 @@
import android.Manifest;
import android.accounts.Account;
+import android.accounts.AccountManagerInternal;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -28,7 +29,10 @@
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.compat.CompatChanges;
import android.app.job.JobInfo;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -106,6 +110,13 @@
*/
private static final long BACKGROUND_OBSERVER_DELAY = 10 * DateUtils.SECOND_IN_MILLIS;
+ /**
+ * Enables checking for account access for the calling uid on all sync-related APIs.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2)
+ public static final long ACCOUNT_ACCESS_CHECK_CHANGE_ID = 201794303L;
+
public static class Lifecycle extends SystemService {
private ContentService mService;
@@ -157,6 +168,8 @@
private SyncManager mSyncManager = null;
private final Object mSyncManagerLock = new Object();
+ private final AccountManagerInternal mAccountManagerInternal;
+
private static final BinderDeathDispatcher<IContentObserver> sObserverDeathDispatcher =
new BinderDeathDispatcher<>();
@@ -317,6 +330,8 @@
localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
localeFilter, null, null);
+
+ mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
}
void onBootPhase(int phase) {
@@ -593,6 +608,10 @@
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
+
validateExtras(callingUid, extras);
final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras);
@@ -642,11 +661,14 @@
@Override
public void syncAsUser(SyncRequest request, int userId, String callingPackage) {
enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId);
+
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+ if (!hasAccountAccess(true, request.getAccount(), callingUid)) {
+ return;
+ }
final Bundle extras = request.getBundle();
-
validateExtras(callingUid, extras);
final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras);
@@ -853,6 +875,9 @@
"no permission to read the sync settings for user " + userId);
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return false;
+ }
final long identityToken = clearCallingIdentity();
try {
@@ -882,8 +907,13 @@
"no permission to write the sync settings");
enforceCrossUserPermission(userId,
"no permission to modify the sync settings for user " + userId);
+
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
+
final int syncExemptionFlag = getSyncExemptionForCaller(callingUid);
final long identityToken = clearCallingIdentity();
@@ -912,7 +942,11 @@
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
- validateExtras(Binder.getCallingUid(), extras);
+ final int callingUid = Binder.getCallingUid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
+ validateExtras(callingUid, extras);
int userId = UserHandle.getCallingUserId();
@@ -942,9 +976,11 @@
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
- validateExtras(Binder.getCallingUid(), extras);
-
final int callingUid = Binder.getCallingUid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
+ validateExtras(callingUid, extras);
int userId = UserHandle.getCallingUserId();
final long identityToken = clearCallingIdentity();
@@ -969,6 +1005,9 @@
}
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return new ArrayList<>(); // return a new empty list for consistent behavior
+ }
int userId = UserHandle.getCallingUserId();
final long identityToken = clearCallingIdentity();
@@ -995,6 +1034,9 @@
"no permission to read the sync settings for user " + userId);
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; // to keep behavior consistent
+ }
final long identityToken = clearCallingIdentity();
try {
@@ -1031,6 +1073,9 @@
syncable = normalizeSyncable(syncable);
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
final long identityToken = clearCallingIdentity();
try {
@@ -1103,6 +1148,10 @@
public boolean isSyncActive(Account account, String authority, ComponentName cname) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return false;
+ }
+
int userId = UserHandle.getCallingUserId();
final long identityToken = clearCallingIdentity();
try {
@@ -1165,6 +1214,9 @@
"no permission to read the sync stats for user " + userId);
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return null;
+ }
final long identityToken = clearCallingIdentity();
try {
@@ -1196,6 +1248,10 @@
"no permission to read the sync stats");
enforceCrossUserPermission(userId,
"no permission to retrieve the sync settings for user " + userId);
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return false;
+ }
+
final long identityToken = clearCallingIdentity();
SyncManager syncManager = getSyncManager();
if (syncManager == null) return false;
@@ -1405,6 +1461,32 @@
Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
}
+ /**
+ * Checks to see if the given account is accessible by the provided uid.
+ *
+ * @param checkCompatFlag whether to check if the ACCOUNT_ACCESS_CHECK_CHANGE_ID flag is enabled
+ * @param account the account trying to be accessed
+ * @param uid the uid trying to access the account
+ * @return {@code true} if the account is accessible by the given uid, {@code false} otherwise
+ */
+ private boolean hasAccountAccess(boolean checkCompatFlag, Account account, int uid) {
+ if (account == null) {
+ // If the account is null, it means to check for all accounts hence skip the check here.
+ return true;
+ }
+ if (checkCompatFlag
+ && !CompatChanges.isChangeEnabled(ACCOUNT_ACCESS_CHECK_CHANGE_ID, uid)) {
+ return true;
+ }
+
+ final long identityToken = clearCallingIdentity();
+ try {
+ return mAccountManagerInternal.hasAccountAccess(account, uid);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
private static int normalizeSyncable(int syncable) {
if (syncable > 0) {
return SyncStorageEngine.AuthorityInfo.SYNCABLE;
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 7cb2921..cb04ddf 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -156,9 +156,15 @@
mMode = mode;
+ DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
+ if (displayInfo == null) {
+ // displayInfo can be null if the associated display has been removed. There
+ // is a delay between the display being removed and ColorFade being dismissed.
+ return false;
+ }
+
// Get the display size and layer stack.
// This is not expected to change while the color fade surface is showing.
- DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
mDisplayLayerStack = displayInfo.layerStack;
mDisplayWidth = displayInfo.getNaturalWidth();
mDisplayHeight = displayInfo.getNaturalHeight();
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 7a0cf4b..540ae81 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -73,6 +73,8 @@
private final SurfaceControlProxy mSurfaceControlProxy;
+ private final boolean mIsBootDisplayModeSupported;
+
// Called with SyncRoot lock held.
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener) {
@@ -85,6 +87,7 @@
super(syncRoot, context, handler, listener, TAG);
mInjector = injector;
mSurfaceControlProxy = mInjector.getSurfaceControlProxy();
+ mIsBootDisplayModeSupported = mSurfaceControlProxy.getBootDisplayModeSupport();
}
@Override
@@ -349,8 +352,7 @@
if (preferredRecord != null) {
int preferredModeId = preferredRecord.mMode.getModeId();
- if (mSurfaceControlProxy.getBootDisplayModeSupport()
- && mSystemPreferredModeId != preferredModeId) {
+ if (mIsBootDisplayModeSupported && mSystemPreferredModeId != preferredModeId) {
mSystemPreferredModeId = preferredModeId;
preferredModeChanged = true;
}
@@ -900,7 +902,7 @@
}
updateDeviceInfoLocked();
- if (!mSurfaceControlProxy.getBootDisplayModeSupport()) {
+ if (!mIsBootDisplayModeSupported) {
return;
}
if (mUserPreferredModeId == INVALID_MODE_ID) {
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 22d32a6..50f5536 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -467,7 +467,9 @@
}
mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
- mAtmInternal.notifyDreamStateChanged(false);
+ mHandler.post(() -> {
+ mAtmInternal.notifyDreamStateChanged(false);
+ });
}
private void checkPermission(String permission) {
diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java
index 176c08c..924db6a 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerService.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerService.java
@@ -22,12 +22,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ILocaleManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.res.Configuration;
import android.os.Binder;
import android.os.HandlerThread;
import android.os.LocaleList;
@@ -154,6 +156,12 @@
}
@Override
+ @NonNull
+ public LocaleList getSystemLocales() throws RemoteException {
+ return LocaleManagerService.this.getSystemLocales();
+ }
+
+ @Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
@@ -426,6 +434,32 @@
return null;
}
+ /**
+ * Returns the current system locales.
+ */
+ @NonNull
+ public LocaleList getSystemLocales() throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return getSystemLocalesUnchecked();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @NonNull
+ private LocaleList getSystemLocalesUnchecked() throws RemoteException {
+ LocaleList systemLocales = null;
+ Configuration conf = ActivityManager.getService().getConfiguration();
+ if (conf != null) {
+ systemLocales = conf.getLocales();
+ }
+ if (systemLocales == null) {
+ systemLocales = LocaleList.getEmptyLocaleList();
+ }
+ return systemLocales;
+ }
+
private void logMetric(@NonNull AppLocaleChangedAtomRecord atomRecordForMetrics) {
FrameworkStatsLog.write(FrameworkStatsLog.APPLICATION_LOCALES_CHANGED,
atomRecordForMetrics.mCallingUid,
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 3ce8e46..1937852 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -45,6 +45,7 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
+import android.window.WindowContainerToken;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
@@ -410,6 +411,7 @@
private IBinder mToken;
private IBinder.DeathRecipient mDeathEater;
private boolean mRestoreSystemAlertWindow;
+ private WindowContainerToken mTaskRecordingWindowContainerToken = null;
MediaProjection(int type, int uid, String packageName, int targetSdkVersion,
boolean isPrivileged) {
@@ -568,7 +570,7 @@
}
}
- @Override
+ @Override // Binder call
public void registerCallback(IMediaProjectionCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
@@ -576,7 +578,7 @@
mCallbackDelegate.add(callback);
}
- @Override
+ @Override // Binder call
public void unregisterCallback(IMediaProjectionCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
@@ -584,6 +586,17 @@
mCallbackDelegate.remove(callback);
}
+ @Override // Binder call
+ public void setTaskRecordingWindowContainerToken(WindowContainerToken token) {
+ // TODO(b/221417940) set the task id to record from sysui, for the package chosen.
+ mTaskRecordingWindowContainerToken = token;
+ }
+
+ @Override // Binder call
+ public WindowContainerToken getTaskRecordingWindowContainerToken() {
+ return mTaskRecordingWindowContainerToken;
+ }
+
public MediaProjectionInfo getProjectionInfo() {
return new MediaProjectionInfo(packageName, userHandle);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 9f573c2..57ffba7 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -4094,7 +4094,7 @@
"updateNetworkStats: " + uid + "/" + (uidForeground ? "F" : "B"));
}
try {
- mNetworkStats.setUidForeground(uid, uidForeground);
+ mNetworkStats.noteUidForeground(uid, uidForeground);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
@@ -5421,6 +5421,11 @@
try {
mNetworkManager.setUidOnMeteredNetworkDenylist(uid, enable);
mLogger.meteredAllowlistChanged(uid, enable);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setUidOnMeteredNetworkDenylist(sdkSandboxUid, enable);
+ mLogger.meteredAllowlistChanged(sdkSandboxUid, enable);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting denylist (" + enable + ") rules for " + uid, e);
} catch (RemoteException e) {
@@ -5433,6 +5438,11 @@
try {
mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, enable);
mLogger.meteredDenylistChanged(uid, enable);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setUidOnMeteredNetworkAllowlist(sdkSandboxUid, enable);
+ mLogger.meteredDenylistChanged(sdkSandboxUid, enable);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting allowlist (" + enable + ") rules for " + uid, e);
} catch (RemoteException e) {
@@ -5471,12 +5481,31 @@
}
}
+ private void addSdkSandboxUidsIfNeeded(SparseIntArray uidRules) {
+ final int size = uidRules.size();
+ final SparseIntArray sdkSandboxUids = new SparseIntArray();
+ for (int index = 0; index < size; index++) {
+ final int uid = uidRules.keyAt(index);
+ final int rule = uidRules.valueAt(index);
+ if (Process.isApplicationUid(uid)) {
+ sdkSandboxUids.put(Process.toSdkSandboxUid(uid), rule);
+ }
+ }
+
+ for (int index = 0; index < sdkSandboxUids.size(); index++) {
+ final int uid = sdkSandboxUids.keyAt(index);
+ final int rule = sdkSandboxUids.valueAt(index);
+ uidRules.put(uid, rule);
+ }
+ }
+
/**
* Set uid rules on a particular firewall chain. This is going to synchronize the rules given
* here to netd. It will clean up dead rules and make sure the target chain only contains rules
* specified here.
*/
private void setUidFirewallRulesUL(int chain, SparseIntArray uidRules) {
+ addSdkSandboxUidsIfNeeded(uidRules);
try {
int size = uidRules.size();
int[] uids = new int[size];
@@ -5519,6 +5548,11 @@
try {
mNetworkManager.setFirewallUidRule(chain, uid, rule);
mLogger.uidFirewallRuleChanged(chain, uid, rule);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setFirewallUidRule(chain, sdkSandboxUid, rule);
+ mLogger.uidFirewallRuleChanged(chain, sdkSandboxUid, rule);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting firewall uid rules", e);
} catch (RemoteException e) {
@@ -5555,15 +5589,16 @@
*/
private void resetUidFirewallRules(int uid) {
try {
- mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid,
- FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid,
+ FIREWALL_RULE_DEFAULT);
mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false);
mLogger.meteredAllowlistChanged(uid, false);
mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false);
@@ -5573,6 +5608,9 @@
} catch (RemoteException e) {
// ignored; service lives in system_server
}
+ if (Process.isApplicationUid(uid)) {
+ resetUidFirewallRules(Process.toSdkSandboxUid(uid));
+ }
}
@Deprecated
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 93f1b47..9e0c975 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -104,6 +104,7 @@
// The amount of time rules instances can exist without their owning app being installed.
private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
+ static final int RULE_LIMIT_PER_PACKAGE = 100;
// pkg|userId => uid
protected final ArrayMap<String, Integer> mRulesUidCache = new ArrayMap<>();
@@ -329,10 +330,10 @@
int newRuleInstanceCount = getCurrentInstanceCount(automaticZenRule.getOwner())
+ getCurrentInstanceCount(automaticZenRule.getConfigurationActivity())
+ 1;
- if (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount) {
+ if (newRuleInstanceCount > RULE_LIMIT_PER_PACKAGE
+ || (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount)) {
throw new IllegalArgumentException("Rule instance limit exceeded");
}
-
}
ZenModeConfig newConfig;
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 9ff4aab..d26a1ac 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -253,7 +253,8 @@
*
* <p>This is only for shell command and only root or shell user can use this.
*
- * @param packageNames dex optimize the passed packages or all packages if null
+ * @param packageNames dex optimize the passed packages in the given order, or all packages in
+ * the default order if null
*
* @return true if dex optimization is complete. false if the task is cancelled or if there was
* an error.
@@ -268,11 +269,11 @@
resetStatesForNewDexOptRunLocked(Thread.currentThread());
}
PackageManagerService pm = mInjector.getPackageManagerService();
- ArraySet<String> packagesToOptimize;
+ List<String> packagesToOptimize;
if (packageNames == null) {
packagesToOptimize = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
} else {
- packagesToOptimize = new ArraySet<>(packageNames);
+ packagesToOptimize = packageNames;
}
return runIdleOptimization(pm, packagesToOptimize, /* isPostBootUpdate= */ false);
} finally {
@@ -335,7 +336,7 @@
return false;
}
- ArraySet<String> pkgs = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
+ List<String> pkgs = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
if (pkgs.isEmpty()) {
Slog.i(TAG, "No packages to optimize");
markPostBootUpdateCompleted(params);
@@ -525,7 +526,7 @@
}
/** Returns true if completed */
- private boolean runIdleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
+ private boolean runIdleOptimization(PackageManagerService pm, List<String> pkgs,
boolean isPostBootUpdate) {
synchronized (mLock) {
mLastExecutionStartTimeMs = SystemClock.elapsedRealtime();
@@ -581,10 +582,9 @@
}
@Status
- private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
+ private int idleOptimizePackages(PackageManagerService pm, List<String> pkgs,
long lowStorageThreshold, boolean isPostBootUpdate) {
ArraySet<String> updatedPackages = new ArraySet<>();
- ArraySet<String> updatedPackagesDueToSecondaryDex = new ArraySet<>();
try {
boolean supportSecondaryDex = mInjector.supportSecondaryDex();
@@ -640,25 +640,12 @@
}
}
- pkgs = new ArraySet<>(pkgs);
+ pkgs = new ArrayList<>(pkgs);
pkgs.removeAll(unusedPackages);
}
}
- @Status int primaryResult = optimizePackages(pkgs, lowStorageThreshold,
- /*isForPrimaryDex=*/ true, updatedPackages, isPostBootUpdate);
- if (primaryResult != STATUS_OK) {
- return primaryResult;
- }
-
- if (!supportSecondaryDex) {
- return STATUS_OK;
- }
-
- @Status int secondaryResult = optimizePackages(pkgs, lowStorageThreshold,
- /*isForPrimaryDex*/ false, updatedPackagesDueToSecondaryDex,
- isPostBootUpdate);
- return secondaryResult;
+ return optimizePackages(pkgs, lowStorageThreshold, updatedPackages, isPostBootUpdate);
} finally {
// Always let the pinner service know about changes.
notifyPinService(updatedPackages);
@@ -670,8 +657,10 @@
}
@Status
- private int optimizePackages(ArraySet<String> pkgs, long lowStorageThreshold,
- boolean isForPrimaryDex, ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
+ private int optimizePackages(List<String> pkgs, long lowStorageThreshold,
+ ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
+ boolean supportSecondaryDex = mInjector.supportSecondaryDex();
+
for (String pkg : pkgs) {
int abortCode = abortIdleOptimizations(lowStorageThreshold);
if (abortCode != STATUS_OK) {
@@ -679,11 +668,23 @@
return abortCode;
}
- @DexOptResult int result = optimizePackage(pkg, isForPrimaryDex, isPostBootUpdate);
- if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
+ @DexOptResult int primaryResult =
+ optimizePackage(pkg, true /* isForPrimaryDex */, isPostBootUpdate);
+ if (primaryResult == PackageDexOptimizer.DEX_OPT_PERFORMED) {
updatedPackages.add(pkg);
- } else if (result != PackageDexOptimizer.DEX_OPT_SKIPPED) {
- return convertPackageDexOptimizerStatusToInternal(result);
+ } else if (primaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
+ return convertPackageDexOptimizerStatusToInternal(primaryResult);
+ }
+
+ if (!supportSecondaryDex) {
+ continue;
+ }
+
+ @DexOptResult int secondaryResult =
+ optimizePackage(pkg, false /* isForPrimaryDex */, isPostBootUpdate);
+ if (secondaryResult != PackageDexOptimizer.DEX_OPT_PERFORMED
+ && secondaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
+ return convertPackageDexOptimizerStatusToInternal(secondaryResult);
}
}
return STATUS_OK;
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index 50b2e23..bb2ba5c 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -293,8 +293,8 @@
MetricsLogger.histogram(mPm.mContext, "opt_dialog_time_s", elapsedTimeSeconds);
}
- public ArraySet<String> getOptimizablePackages(@NonNull Computer snapshot) {
- ArraySet<String> pkgs = new ArraySet<>();
+ public List<String> getOptimizablePackages(@NonNull Computer snapshot) {
+ ArrayList<String> pkgs = new ArrayList<>();
mPm.forEachPackageState(snapshot, packageState -> {
final AndroidPackage pkg = packageState.getPkg();
if (pkg != null && mPm.mPackageDexOptimizer.canOptimizePackage(pkg)) {
diff --git a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
similarity index 65%
rename from services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
rename to services/core/java/com/android/server/pm/InitAppsHelper.java
index 91750de..15f26e7 100644
--- a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -32,6 +32,7 @@
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_CHECK_MAX_SDK_VERSION;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.os.Environment;
@@ -61,14 +62,24 @@
* further cleanup and eventually all the installation/scanning related logic will go to another
* class.
*/
-final class InitAndSystemPackageHelper {
+final class InitAppsHelper {
private final PackageManagerService mPm;
-
private final List<ScanPartition> mDirsToScanAsSystem;
private final int mScanFlags;
private final int mSystemParseFlags;
private final int mSystemScanFlags;
private final InstallPackageHelper mInstallPackageHelper;
+ private final ApexManager mApexManager;
+ private final ExecutorService mExecutorService;
+ /* Tracks how long system scan took */
+ private long mSystemScanTime;
+ /* Track of the number of cached system apps */
+ private int mCachedSystemApps;
+ /* Track of the number of system apps */
+ private int mSystemPackagesCount;
+ private final boolean mIsDeviceUpgrading;
+ private final boolean mIsOnlyCoreApps;
+ private final List<ScanPartition> mSystemPartitions;
/**
* Tracks new system packages [received in an OTA] that we expect to
@@ -76,21 +87,33 @@
* are package location.
*/
private final ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
+ /* Tracks of any system packages that no longer exist that needs to be pruned. */
+ private final List<String> mPossiblyDeletedUpdatedSystemApps = new ArrayList<>();
+ // Tracks of stub packages that must either be replaced with full versions in the /data
+ // partition or be disabled.
+ private final List<String> mStubSystemApps = new ArrayList<>();
// TODO(b/198166813): remove PMS dependency
- InitAndSystemPackageHelper(PackageManagerService pm) {
+ InitAppsHelper(PackageManagerService pm, ApexManager apexManager,
+ InstallPackageHelper installPackageHelper,
+ List<ScanPartition> systemPartitions) {
mPm = pm;
- mInstallPackageHelper = new InstallPackageHelper(pm);
+ mApexManager = apexManager;
+ mInstallPackageHelper = installPackageHelper;
+ mSystemPartitions = systemPartitions;
mDirsToScanAsSystem = getSystemScanPartitions();
+ mIsDeviceUpgrading = mPm.isDeviceUpgrading();
+ mIsOnlyCoreApps = mPm.isOnlyCoreApps();
// Set flag to monitor and not change apk file paths when scanning install directories.
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
- if (mPm.isDeviceUpgrading() || mPm.isFirstBoot()) {
+ if (mIsDeviceUpgrading || mPm.isFirstBoot()) {
mScanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
} else {
mScanFlags = scanFlags;
}
mSystemParseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
mSystemScanFlags = scanFlags | SCAN_AS_SYSTEM;
+ mExecutorService = ParallelPackageParser.makeExecutorService();
}
private List<File> getFrameworkResApkSplitFiles() {
@@ -118,7 +141,7 @@
private List<ScanPartition> getSystemScanPartitions() {
final List<ScanPartition> scanPartitions = new ArrayList<>();
- scanPartitions.addAll(mPm.mInjector.getSystemPartitions());
+ scanPartitions.addAll(mSystemPartitions);
scanPartitions.addAll(getApexScanPartitions());
Slog.d(TAG, "Directories scanned as system partitions: " + scanPartitions);
return scanPartitions;
@@ -126,8 +149,7 @@
private List<ScanPartition> getApexScanPartitions() {
final List<ScanPartition> scanPartitions = new ArrayList<>();
- final List<ApexManager.ActiveApexInfo> activeApexInfos =
- mPm.mApexManager.getActiveApexInfos();
+ final List<ApexManager.ActiveApexInfo> activeApexInfos = mApexManager.getActiveApexInfos();
for (int i = 0; i < activeApexInfos.size(); i++) {
final ScanPartition scanPartition = resolveApexToScanPartition(activeApexInfos.get(i));
if (scanPartition != null) {
@@ -144,117 +166,134 @@
if (apexInfo.preInstalledApexPath.getAbsolutePath().equals(
sp.getFolder().getAbsolutePath())
|| apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
- sp.getFolder().getAbsolutePath() + File.separator)) {
+ sp.getFolder().getAbsolutePath() + File.separator)) {
return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX);
}
}
return null;
}
- public OverlayConfig initPackages(
- WatchedArrayMap<String, PackageSetting> packageSettings, int[] userIds,
- long startTime) {
- PackageParser2 packageParser = mPm.mInjector.getScanningCachingPackageParser();
-
- ExecutorService executorService = ParallelPackageParser.makeExecutorService();
+ /**
+ * Install apps from system dirs.
+ */
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ public OverlayConfig initSystemApps(PackageParser2 packageParser,
+ WatchedArrayMap<String, PackageSetting> packageSettings,
+ int[] userIds, long startTime) {
// Prepare apex package info before scanning APKs, this information is needed when
// scanning apk in apex.
- mPm.mApexManager.scanApexPackagesTraced(packageParser, executorService);
+ mApexManager.scanApexPackagesTraced(packageParser, mExecutorService);
- scanSystemDirs(packageParser, executorService);
+ scanSystemDirs(packageParser, mExecutorService);
// Parse overlay configuration files to set default enable state, mutability, and
// priority of system overlays.
final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>();
- for (ApexManager.ActiveApexInfo apexInfo : mPm.mApexManager.getActiveApexInfos()) {
- for (String packageName : mPm.mApexManager.getApksInApex(apexInfo.apexModuleName)) {
+ for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) {
+ for (String packageName : mApexManager.getApksInApex(apexInfo.apexModuleName)) {
apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath);
}
}
- OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
+ final OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
consumer -> mPm.forEachPackage(mPm.snapshotComputer(),
pkg -> consumer.accept(pkg, pkg.isSystem(),
- apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
- // Prune any system packages that no longer exist.
- final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
- // Stub packages must either be replaced with full versions in the /data
- // partition or be disabled.
- final List<String> stubSystemApps = new ArrayList<>();
+ apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
- if (!mPm.isOnlyCoreApps()) {
+ if (!mIsOnlyCoreApps) {
// do this first before mucking with mPackages for the "expecting better" case
- updateStubSystemAppsList(stubSystemApps);
+ updateStubSystemAppsList(mStubSystemApps);
mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings,
- possiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
+ mPossiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
}
- final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
+ logSystemAppsScanningTime(startTime);
+ return overlayConfig;
+ }
+
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private void logSystemAppsScanningTime(long startTime) {
+ mCachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
// Remove any shared userIDs that have no associated packages
mPm.mSettings.pruneSharedUsersLPw();
- final long systemScanTime = SystemClock.uptimeMillis() - startTime;
- final int systemPackagesCount = mPm.mPackages.size();
- Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
- + " ms, packageCount: " + systemPackagesCount
+ mSystemScanTime = SystemClock.uptimeMillis() - startTime;
+ mSystemPackagesCount = mPm.mPackages.size();
+ Slog.i(TAG, "Finished scanning system apps. Time: " + mSystemScanTime
+ + " ms, packageCount: " + mSystemPackagesCount
+ " , timePerPackage: "
- + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
- + " , cached: " + cachedSystemApps);
- if (mPm.isDeviceUpgrading() && systemPackagesCount > 0) {
+ + (mSystemPackagesCount == 0 ? 0 : mSystemScanTime / mSystemPackagesCount)
+ + " , cached: " + mCachedSystemApps);
+ if (mIsDeviceUpgrading && mSystemPackagesCount > 0) {
//CHECKSTYLE:OFF IndentationCheck
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
- systemScanTime / systemPackagesCount);
+ mSystemScanTime / mSystemPackagesCount);
//CHECKSTYLE:ON IndentationCheck
}
+ }
- if (!mPm.isOnlyCoreApps()) {
+ /**
+ * Install apps/updates from data dir and fix system apps that are affected.
+ */
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ public void initNonSystemApps(PackageParser2 packageParser, @NonNull int[] userIds,
+ long startTime) {
+ if (!mIsOnlyCoreApps) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirTracedLI(mPm.getAppInstallDir(), /* frameworkSplits= */ null, 0,
- mScanFlags | SCAN_REQUIRE_KNOWN, 0,
- packageParser, executorService);
-
+ mScanFlags | SCAN_REQUIRE_KNOWN,
+ packageParser, mExecutorService);
}
- List<Runnable> unfinishedTasks = executorService.shutdownNow();
+ List<Runnable> unfinishedTasks = mExecutorService.shutdownNow();
if (!unfinishedTasks.isEmpty()) {
throw new IllegalStateException("Not all tasks finished before calling close: "
+ unfinishedTasks);
}
-
- if (!mPm.isOnlyCoreApps()) {
- mInstallPackageHelper.cleanupDisabledPackageSettings(possiblyDeletedUpdatedSystemApps,
- userIds, mScanFlags);
- mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
- stubSystemApps, mSystemScanFlags, mSystemParseFlags);
-
- // Uncompress and install any stubbed system applications.
- // This must be done last to ensure all stubs are replaced or disabled.
- mInstallPackageHelper.installSystemStubPackages(stubSystemApps, mScanFlags);
-
- final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
- - cachedSystemApps;
-
- final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
- final int dataPackagesCount = mPm.mPackages.size() - systemPackagesCount;
- Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
- + " ms, packageCount: " + dataPackagesCount
- + " , timePerPackage: "
- + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
- + " , cached: " + cachedNonSystemApps);
- if (mPm.isDeviceUpgrading() && dataPackagesCount > 0) {
- //CHECKSTYLE:OFF IndentationCheck
- FrameworkStatsLog.write(
- FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
- BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
- dataScanTime / dataPackagesCount);
- //CHECKSTYLE:OFF IndentationCheck
- }
+ if (!mIsOnlyCoreApps) {
+ fixSystemPackages(userIds);
+ logNonSystemAppScanningTime(startTime);
}
mExpectingBetter.clear();
-
mPm.mSettings.pruneRenamedPackagesLPw();
- packageParser.close();
- return overlayConfig;
+ }
+
+ /**
+ * Clean up system packages now that some system package updates have been installed from
+ * the data dir. Also install system stub packages as the last step.
+ */
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private void fixSystemPackages(@NonNull int[] userIds) {
+ mInstallPackageHelper.cleanupDisabledPackageSettings(mPossiblyDeletedUpdatedSystemApps,
+ userIds, mScanFlags);
+ mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
+ mStubSystemApps, mSystemScanFlags, mSystemParseFlags);
+
+ // Uncompress and install any stubbed system applications.
+ // This must be done last to ensure all stubs are replaced or disabled.
+ mInstallPackageHelper.installSystemStubPackages(mStubSystemApps, mScanFlags);
+ }
+
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private void logNonSystemAppScanningTime(long startTime) {
+ final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
+ - mCachedSystemApps;
+
+ final long dataScanTime = SystemClock.uptimeMillis() - mSystemScanTime - startTime;
+ final int dataPackagesCount = mPm.mPackages.size() - mSystemPackagesCount;
+ Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
+ + " ms, packageCount: " + dataPackagesCount
+ + " , timePerPackage: "
+ + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
+ + " , cached: " + cachedNonSystemApps);
+ if (mIsDeviceUpgrading && dataPackagesCount > 0) {
+ //CHECKSTYLE:OFF IndentationCheck
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+ BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
+ dataScanTime / dataPackagesCount);
+ //CHECKSTYLE:OFF IndentationCheck
+ }
}
/**
@@ -274,13 +313,13 @@
continue;
}
scanDirTracedLI(partition.getOverlayFolder(), /* frameworkSplits= */ null,
- mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
+ mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
packageParser, executorService);
}
scanDirTracedLI(frameworkDir, null,
mSystemParseFlags,
- mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
+ mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,
packageParser, executorService);
if (!mPm.mPackages.containsKey("android")) {
throw new IllegalStateException(
@@ -292,11 +331,11 @@
if (partition.getPrivAppFolder() != null) {
scanDirTracedLI(partition.getPrivAppFolder(), /* frameworkSplits= */ null,
mSystemParseFlags,
- mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
+ mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,
packageParser, executorService);
}
scanDirTracedLI(partition.getAppFolder(), /* frameworkSplits= */ null,
- mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
+ mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
packageParser, executorService);
}
}
@@ -315,7 +354,7 @@
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private void scanDirTracedLI(File scanDir, List<File> frameworkSplits,
int parseFlags, int scanFlags,
- long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
+ PackageParser2 packageParser, ExecutorService executorService) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
@@ -323,7 +362,7 @@
parseFlags |= PARSE_CHECK_MAX_SDK_VERSION;
}
mInstallPackageHelper.installPackagesFromDir(scanDir, frameworkSplits, parseFlags,
- scanFlags, currentTime, packageParser, executorService);
+ scanFlags, packageParser, executorService);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index b39b24f..870a11a 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -3062,7 +3062,7 @@
final RemovePackageHelper removePackageHelper = new RemovePackageHelper(mPm);
removePackageHelper.removePackageLI(stubPkg, true /*chatty*/);
try {
- return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
+ return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
e);
@@ -3194,7 +3194,7 @@
| ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
@PackageManagerService.ScanFlags int scanFlags = mPm.getSystemPackageScanFlags(codePath);
final AndroidPackage pkg = scanSystemPackageTracedLI(
- codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
+ codePath, parseFlags, scanFlags, null);
PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
@@ -3368,7 +3368,7 @@
mRemovePackageHelper.removePackageLI(pkg, true);
try {
final File codePath = new File(pkg.getPath());
- scanSystemPackageTracedLI(codePath, 0, scanFlags, 0, null);
+ scanSystemPackageTracedLI(codePath, 0, scanFlags, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse updated, ex-system package: "
+ e.getMessage());
@@ -3389,7 +3389,7 @@
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public void installPackagesFromDir(File scanDir, List<File> frameworkSplits, int parseFlags,
- int scanFlags, long currentTime, PackageParser2 packageParser,
+ int scanFlags, PackageParser2 packageParser,
ExecutorService executorService) {
final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
@@ -3432,7 +3432,7 @@
parseResult.parsedPackage);
}
try {
- addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, currentTime,
+ addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
null);
} catch (PackageManagerException e) {
errorCode = e.error;
@@ -3495,7 +3495,7 @@
try {
final AndroidPackage newPkg = scanSystemPackageTracedLI(
- scanFile, reparseFlags, rescanFlags, 0, null);
+ scanFile, reparseFlags, rescanFlags, null);
// We rescanned a stub, add it to the list of stubbed system packages
if (newPkg.isStub()) {
stubSystemApps.add(packageName);
@@ -3509,14 +3509,14 @@
/**
* Traces a package scan.
- * @see #scanSystemPackageLI(File, int, int, long, UserHandle)
+ * @see #scanSystemPackageLI(File, int, int, UserHandle)
*/
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public AndroidPackage scanSystemPackageTracedLI(File scanFile, final int parseFlags,
- int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
+ int scanFlags, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
try {
- return scanSystemPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
+ return scanSystemPackageLI(scanFile, parseFlags, scanFlags, user);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -3528,7 +3528,7 @@
*/
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private AndroidPackage scanSystemPackageLI(File scanFile, int parseFlags, int scanFlags,
- long currentTime, UserHandle user) throws PackageManagerException {
+ UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
@@ -3544,7 +3544,7 @@
PackageManagerService.renameStaticSharedLibraryPackage(parsedPackage);
}
- return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
+ return addForInitLI(parsedPackage, parseFlags, scanFlags, user);
}
/**
@@ -3563,11 +3563,11 @@
@GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
@ParsingPackageUtils.ParseFlags int parseFlags,
- @PackageManagerService.ScanFlags int scanFlags, long currentTime,
+ @PackageManagerService.ScanFlags int scanFlags,
@Nullable UserHandle user) throws PackageManagerException {
final Pair<ScanResult, Boolean> scanResultPair = scanSystemPackageLI(
- parsedPackage, parseFlags, scanFlags, currentTime, user);
+ parsedPackage, parseFlags, scanFlags, user);
final ScanResult scanResult = scanResultPair.first;
boolean shouldHideSystemApp = scanResultPair.second;
if (scanResult.mSuccess) {
@@ -3762,7 +3762,7 @@
private Pair<ScanResult, Boolean> scanSystemPackageLI(ParsedPackage parsedPackage,
@ParsingPackageUtils.ParseFlags int parseFlags,
- @PackageManagerService.ScanFlags int scanFlags, long currentTime,
+ @PackageManagerService.ScanFlags int scanFlags,
@Nullable UserHandle user) throws PackageManagerException {
final boolean scanSystemPartition =
(parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
@@ -3950,7 +3950,7 @@
}
final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags,
- scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
+ scanFlags | SCAN_UPDATE_SIGNATURE, 0 /* currentTime */, user, null);
return new Pair<>(scanResult, shouldHideSystemApp);
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 76b9830..5902f48 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -27,6 +27,7 @@
import android.os.CreateAppDataResult;
import android.os.IBinder;
import android.os.IInstalld;
+import android.os.ReconcileSdkDataArgs;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.storage.CrateMetadata;
@@ -215,6 +216,21 @@
return result;
}
+ static ReconcileSdkDataArgs buildReconcileSdkDataArgs(String uuid, String packageName,
+ List<String> subDirNames, int userId, int appId,
+ String seInfo, int flags) {
+ final ReconcileSdkDataArgs args = new ReconcileSdkDataArgs();
+ args.uuid = uuid;
+ args.packageName = packageName;
+ args.subDirNames = subDirNames;
+ args.userId = userId;
+ args.appId = appId;
+ args.previousAppId = 0;
+ args.seInfo = seInfo;
+ args.flags = flags;
+ return args;
+ }
+
public @NonNull CreateAppDataResult createAppData(@NonNull CreateAppDataArgs args)
throws InstallerException {
if (!checkBeforeRemote()) {
@@ -247,6 +263,18 @@
}
}
+ void reconcileSdkData(@NonNull ReconcileSdkDataArgs args)
+ throws InstallerException {
+ if (!checkBeforeRemote()) {
+ return;
+ }
+ try {
+ mInstalld.reconcileSdkData(args);
+ } catch (Exception e) {
+ throw InstallerException.from(e);
+ }
+ }
+
/**
* Class that collects multiple {@code installd} operations together in an
* attempt to more efficiently execute them in bulk.
diff --git a/services/core/java/com/android/server/pm/PackageManagerLocal.java b/services/core/java/com/android/server/pm/PackageManagerLocal.java
index 7b76567..39cc37e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerLocal.java
+++ b/services/core/java/com/android/server/pm/PackageManagerLocal.java
@@ -16,8 +16,16 @@
package com.android.server.pm;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
/**
* In-process API for server side PackageManager related infrastructure.
*
@@ -28,4 +36,48 @@
*/
@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public interface PackageManagerLocal {
+
+ /**
+ * Indicates if operation should include device encrypted storage.
+ */
+ int FLAG_STORAGE_DE = Installer.FLAG_STORAGE_DE;
+ /**
+ * Indicates if operation should include credential encrypted storage.
+ */
+ int FLAG_STORAGE_CE = Installer.FLAG_STORAGE_CE;
+
+ /**
+ * Constants for use with {@link #reconcileSdkData} to specify which storage areas should be
+ * included for operation.
+ *
+ * @hide
+ */
+ @IntDef(prefix = "FLAG_STORAGE_", value = {
+ FLAG_STORAGE_DE,
+ FLAG_STORAGE_CE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StorageFlags {}
+
+ /**
+ * Reconcile sdk data sub-directories for the given {@code packagName}.
+ *
+ * Sub directories are created if they do not exist already. If there is an existing per-
+ * sdk directory that is missing from {@code subDirNames}, then it is removed.
+ *
+ * Sdk package path is created if it doesn't exist before creating per-sdk directories.
+ *
+ * @param volumeUuid the volume in which the sdk data should be prepared.
+ * @param packageName package name of the app for which sdk data directory will be prepared.
+ * @param subDirNames names of sub directories that should be reconciled against.
+ * @param userId id of the user to whom the package belongs to.
+ * @param appId id of the package.
+ * @param previousAppId previous id of the package if package is being updated.
+ * @param flags flags from StorageManager to indicate which storage areas should be included.
+ * @param seInfo seInfo tag to be used for selinux policy.
+ * @throws IOException If any error occurs during the operation.
+ */
+ void reconcileSdkData(@Nullable String volumeUuid, @NonNull String packageName,
+ @NonNull List<String> subDirNames, int userId, int appId, int previousAppId,
+ @NonNull String seInfo, @StorageFlags int flags) throws IOException;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 67056ea..b1b05be 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -132,6 +132,7 @@
import android.os.ParcelableException;
import android.os.PersistableBundle;
import android.os.Process;
+import android.os.ReconcileSdkDataArgs;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -228,7 +229,6 @@
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationService;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
-import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
import com.android.server.sdksandbox.SdkSandboxManagerLocal;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.utils.SnapshotCache;
@@ -935,7 +935,7 @@
private final BroadcastHelper mBroadcastHelper;
private final RemovePackageHelper mRemovePackageHelper;
private final DeletePackageHelper mDeletePackageHelper;
- private final InitAndSystemPackageHelper mInitAndSystemPackageHelper;
+ private final InitAppsHelper mInitAppsHelper;
private final AppDataHelper mAppDataHelper;
private final InstallPackageHelper mInstallPackageHelper;
private final PreferredActivityHelper mPreferredActivityHelper;
@@ -1670,7 +1670,7 @@
mAppDataHelper = testParams.appDataHelper;
mInstallPackageHelper = testParams.installPackageHelper;
mRemovePackageHelper = testParams.removePackageHelper;
- mInitAndSystemPackageHelper = testParams.initAndSystemPackageHelper;
+ mInitAppsHelper = testParams.initAndSystemPackageHelper;
mDeletePackageHelper = testParams.deletePackageHelper;
mPreferredActivityHelper = testParams.preferredActivityHelper;
mResolveIntentHelper = testParams.resolveIntentHelper;
@@ -1820,7 +1820,8 @@
mAppDataHelper = new AppDataHelper(this);
mInstallPackageHelper = new InstallPackageHelper(this, mAppDataHelper);
mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
- mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this);
+ mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
+ mInjector.getSystemPartitions());
mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
mAppDataHelper);
mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
@@ -1955,8 +1956,11 @@
mIsEngBuild, mIsUserDebugBuild, mIncrementalVersion);
final int[] userIds = mUserManager.getUserIds();
- mOverlayConfig = mInitAndSystemPackageHelper.initPackages(packageSettings,
- userIds, startTime);
+ PackageParser2 packageParser = mInjector.getScanningCachingPackageParser();
+ mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds,
+ startTime);
+ mInitAppsHelper.initNonSystemApps(packageParser, userIds, startTime);
+ packageParser.close();
// Resolve the storage manager.
mStorageManagerPackage = getStorageManagerPackageName(computer);
@@ -6032,6 +6036,22 @@
}
private class PackageManagerLocalImpl implements PackageManagerLocal {
+ @Override
+ public void reconcileSdkData(@Nullable String volumeUuid, @NonNull String packageName,
+ @NonNull List<String> subDirNames, int userId, int appId, int previousAppId,
+ @NonNull String seInfo, int flags) throws IOException {
+ synchronized (mInstallLock) {
+ ReconcileSdkDataArgs args = mInstaller.buildReconcileSdkDataArgs(volumeUuid,
+ packageName, subDirNames, userId, appId, seInfo,
+ flags);
+ args.previousAppId = previousAppId;
+ try {
+ mInstaller.reconcileSdkData(args);
+ } catch (InstallerException e) {
+ throw new IOException(e.getMessage());
+ }
+ }
+ }
}
private class PackageManagerInternalImpl extends PackageManagerInternalBase {
@@ -7013,7 +7033,7 @@
}
boolean isExpectingBetter(String packageName) {
- return mInitAndSystemPackageHelper.isExpectingBetter(packageName);
+ return mInitAppsHelper.isExpectingBetter(packageName);
}
int getDefParseFlags() {
@@ -7112,13 +7132,12 @@
}
boolean isOverlayMutable(String packageName) {
- return (mOverlayConfig != null ? mOverlayConfig
- : OverlayConfig.getSystemInstance()).isMutable(packageName);
+ return mOverlayConfig.isMutable(packageName);
}
@ScanFlags int getSystemPackageScanFlags(File codePath) {
List<ScanPartition> dirsToScanAsSystem =
- mInitAndSystemPackageHelper.getDirsToScanAsSystem();
+ mInitAppsHelper.getDirsToScanAsSystem();
@PackageManagerService.ScanFlags int scanFlags = SCAN_AS_SYSTEM;
for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
ScanPartition partition = dirsToScanAsSystem.get(i);
@@ -7136,7 +7155,7 @@
Pair<Integer, Integer> getSystemPackageRescanFlagsAndReparseFlags(File scanFile,
int systemScanFlags, int systemParseFlags) {
List<ScanPartition> dirsToScanAsSystem =
- mInitAndSystemPackageHelper.getDirsToScanAsSystem();
+ mInitAppsHelper.getDirsToScanAsSystem();
@ParsingPackageUtils.ParseFlags int reparseFlags = 0;
@PackageManagerService.ScanFlags int rescanFlags = 0;
for (int i1 = dirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index 5bdda0b..e466fe2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -109,7 +109,7 @@
public AppDataHelper appDataHelper;
public InstallPackageHelper installPackageHelper;
public RemovePackageHelper removePackageHelper;
- public InitAndSystemPackageHelper initAndSystemPackageHelper;
+ public InitAppsHelper initAndSystemPackageHelper;
public DeletePackageHelper deletePackageHelper;
public PreferredActivityHelper preferredActivityHelper;
public ResolveIntentHelper resolveIntentHelper;
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index df19d3e..a991ed3 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -151,7 +151,7 @@
final AndroidPackage pkg;
try {
pkg = installPackageHelper.scanSystemPackageTracedLI(
- ps.getPath(), parseFlags, SCAN_INITIAL, 0, null);
+ ps.getPath(), parseFlags, SCAN_INITIAL, null);
loaded.add(pkg);
} catch (PackageManagerException e) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 34b7ad4..70053bd 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -5409,6 +5409,21 @@
(new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
}
+ private static final String PREFIX_HELP_COMMAND = " ";
+ private static final String PREFIX_HELP_DESCRIPTION = " ";
+ private static final String PREFIX_HELP_DESCRIPTION_EXTRA_LINES = " ";
+
+ private static final String CMD_HELP = "help";
+ private static final String CMD_LIST = "list";
+ private static final String CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS =
+ "report-system-user-package-whitelist-problems";
+
+ private static final String ARG_V = "-v";
+ private static final String ARG_VERBOSE = "--verbose";
+ private static final String ARG_ALL = "--all";
+ private static final String ARG_CRITICAL_ONLY = "--critical-only";
+ private static final String ARG_MODE = "--mode";
+
private int onShellCommand(Shell shell, String cmd) {
if (cmd == null) {
return shell.handleDefaultCommands(cmd);
@@ -5417,9 +5432,9 @@
final PrintWriter pw = shell.getOutPrintWriter();
try {
switch(cmd) {
- case "list":
+ case CMD_LIST:
return runList(pw, shell);
- case "report-system-user-package-whitelist-problems":
+ case CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS:
return runReportPackageWhitelistProblems(pw, shell);
default:
return shell.handleDefaultCommands(cmd);
@@ -5436,10 +5451,10 @@
String opt;
while ((opt = shell.getNextOption()) != null) {
switch (opt) {
- case "-v":
+ case ARG_V:
verbose = true;
break;
- case "--all":
+ case ARG_ALL:
all = true;
break;
default:
@@ -5520,14 +5535,14 @@
String opt;
while ((opt = shell.getNextOption()) != null) {
switch (opt) {
- case "-v":
- case "--verbose":
+ case ARG_V:
+ case ARG_VERBOSE:
verbose = true;
break;
- case "--critical-only":
+ case ARG_CRITICAL_ONLY:
criticalOnly = true;
break;
- case "--mode":
+ case ARG_MODE:
mode = Integer.parseInt(shell.getNextArgRequired());
break;
default:
@@ -6248,20 +6263,28 @@
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
- pw.println("User manager (user) commands:");
- pw.println(" help");
- pw.println(" Prints this help text.");
- pw.println("");
- pw.println(" list [-v] [-all]");
- pw.println(" Prints all users on the system.");
- pw.println(" report-system-user-package-whitelist-problems [-v | --verbose] "
- + "[--critical-only] [--mode MODE]");
- pw.println(" Reports all issues on user-type package whitelist XML files. Options:");
- pw.println(" -v | --verbose : shows extra info, like number of issues");
- pw.println(" --critical-only: show only critical issues, excluding warnings");
- pw.println(" --mode MODE: shows what errors would be if device used mode MODE (where"
- + " MODE is the whitelist mode integer as defined by "
- + "config_userTypePackageWhitelistMode)");
+ pw.printf("User manager (user) commands:\n");
+
+ pw.printf("%s%s\n", PREFIX_HELP_COMMAND, CMD_HELP);
+ pw.printf("%sPrints this help text.\n\n", PREFIX_HELP_DESCRIPTION);
+
+ pw.printf("%s%s [%s] [%s]\n", PREFIX_HELP_COMMAND, CMD_LIST, ARG_V, ARG_ALL);
+ pw.printf("%sPrints all users on the system.\n\n", PREFIX_HELP_DESCRIPTION);
+
+ pw.printf("%s%s [%s | %s] [%s] [%s MODE]\n", PREFIX_HELP_COMMAND,
+ CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS,
+ ARG_V, ARG_VERBOSE, ARG_CRITICAL_ONLY, ARG_MODE);
+
+ pw.printf("%sReports all issues on user-type package allowlist XML files. Options:\n",
+ PREFIX_HELP_DESCRIPTION);
+ pw.printf("%s%s | %s: shows extra info, like number of issues\n",
+ PREFIX_HELP_DESCRIPTION, ARG_V, ARG_VERBOSE);
+ pw.printf("%s%s: show only critical issues, excluding warnings\n",
+ PREFIX_HELP_DESCRIPTION, ARG_CRITICAL_ONLY);
+ pw.printf("%s%s MODE: shows what errors would be if device used mode MODE\n"
+ + "%s(where MODE is the allowlist mode integer as defined by "
+ + "config_userTypePackageWhitelistMode)\n\n",
+ PREFIX_HELP_DESCRIPTION, ARG_MODE, PREFIX_HELP_DESCRIPTION_EXTRA_LINES);
}
}
diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
index 46fde4b..6060233 100644
--- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
+++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
@@ -272,6 +272,10 @@
mHandler.removeCallbacksAndMessages(mToken);
if (importance > IMPORTANCE_CACHED) {
+ if (mRevokeAfterKilledDelay == 0) {
+ onPackageInactiveLocked();
+ return;
+ }
// Delay revocation in case app is restarting
mHandler.postDelayed(() -> {
int imp = mActivityManager.getUidImportance(mUid);
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 71554ee..5a05134b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -562,12 +562,6 @@
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull String packageName,
- @NonNull List<String> permissions) {
- mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions);
- }
-
- @Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName,
int userId) {
return mPermissionManagerServiceImpl.shouldShowRequestPermissionRationale(packageName,
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index d060930..009d155 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -1597,25 +1597,6 @@
}
}
- @Override
- public void revokeOwnPermissionsOnKill(String packageName, List<String> permissions) {
- final int callingUid = Binder.getCallingUid();
- int callingUserId = UserHandle.getUserId(callingUid);
- int targetPackageUid = mPackageManagerInt.getPackageUid(packageName, 0, callingUserId);
- if (targetPackageUid != callingUid) {
- throw new SecurityException("uid " + callingUid
- + " cannot revoke permissions for package " + packageName + " with uid "
- + targetPackageUid);
- }
- for (String permName : permissions) {
- if (!checkCallingOrSelfPermission(permName)) {
- throw new SecurityException("uid " + callingUid + " cannot revoke permission "
- + permName + " because it does not hold that permission");
- }
- }
- mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions);
- }
-
private boolean mayManageRolePermission(int uid) {
final PackageManager packageManager = mContext.getPackageManager();
final String[] packageNames = packageManager.getPackagesForUid(uid);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 3e28320..3771f03 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -327,28 +327,6 @@
void revokePostNotificationPermissionWithoutKillForTest(String packageName, int userId);
/**
- * Triggers the revocation of one or more permissions for a package, under the following
- * conditions:
- * <ul>
- * <li>The package {@code packageName} must be under the same UID as the calling process
- * (typically, the target package is the calling package).
- * <li>Each permission in {@code permissions} must be granted to the package
- * {@code packageName}.
- * <li>Each permission in {@code permissions} must be a runtime permission.
- * </ul>
- * <p>
- * Background permissions which have no corresponding foreground permission still granted once
- * the revocation is effective will also be revoked.
- * <p>
- * This revocation happens asynchronously and kills all processes running in the same UID as
- * {@code packageName}. It will be triggered once it is safe to do so.
- *
- * @param packageName The name of the package for which the permissions will be revoked.
- * @param permissions List of permissions to be revoked.
- */
- void revokeOwnPermissionsOnKill(String packageName, List<String> permissions);
-
- /**
* Get whether you should show UI with rationale for requesting a permission. You should do this
* only if you do not have the permission and the context in which the permission is requested
* does not clearly communicate to the user what would be the benefit from grating this
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 2e60f13..526dccb 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1633,7 +1633,14 @@
if (adapter != null) {
SynchronousResultReceiver bluetoothReceiver =
new SynchronousResultReceiver("bluetooth");
- adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+ adapter.requestControllerActivityEnergyInfo(
+ Runnable::run,
+ info -> {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, info);
+ bluetoothReceiver.send(0, bundle);
+ }
+ );
return awaitControllerInfo(bluetoothReceiver);
} else {
Slog.e(TAG, "Failed to get bluetooth adapter!");
@@ -2338,51 +2345,25 @@
}
int pullProcessDmabufMemory(int atomTag, List<StatsEvent> pulledData) {
- List<ProcessMemoryState> managedProcessList =
- LocalServices.getService(ActivityManagerInternal.class)
- .getMemoryStateForProcesses();
- for (ProcessMemoryState process : managedProcessList) {
- KernelAllocationStats.ProcessDmabuf proc =
- KernelAllocationStats.getDmabufAllocations(process.pid);
- if (proc == null || (proc.retainedBuffersCount <= 0 && proc.mappedBuffersCount <= 0)) {
- continue;
- }
- pulledData.add(
- FrameworkStatsLog.buildStatsEvent(
- atomTag,
- process.uid,
- process.processName,
- process.oomScore,
- proc.retainedSizeKb,
- proc.retainedBuffersCount,
- proc.mappedSizeKb,
- proc.mappedBuffersCount));
+ KernelAllocationStats.ProcessDmabuf[] procBufs =
+ KernelAllocationStats.getDmabufAllocations();
+
+ if (procBufs == null) {
+ return StatsManager.PULL_SKIP;
}
- SparseArray<String> processCmdlines = getProcessCmdlines();
- managedProcessList.forEach(managedProcess -> processCmdlines.delete(managedProcess.pid));
- int size = processCmdlines.size();
- for (int i = 0; i < size; ++i) {
- int pid = processCmdlines.keyAt(i);
- int uid = getUidForPid(pid);
- // ignore root processes (unlikely to be interesting)
- if (uid <= 0) {
- continue;
- }
- KernelAllocationStats.ProcessDmabuf proc =
- KernelAllocationStats.getDmabufAllocations(pid);
- if (proc == null || (proc.retainedBuffersCount <= 0 && proc.mappedBuffersCount <= 0)) {
- continue;
- }
- pulledData.add(
- FrameworkStatsLog.buildStatsEvent(
- atomTag,
- uid,
- processCmdlines.valueAt(i),
- -1001 /*Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.*/,
- proc.retainedSizeKb,
- proc.retainedBuffersCount,
- proc.mappedSizeKb,
- proc.mappedBuffersCount));
+ for (KernelAllocationStats.ProcessDmabuf procBuf : procBufs) {
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag,
+ procBuf.uid,
+ procBuf.processName,
+ procBuf.oomScore,
+ procBuf.retainedSizeKb,
+ procBuf.retainedBuffersCount,
+ 0, /* mapped_dmabuf_kb - deprecated */
+ 0, /* mapped_dmabuf_count - deprecated */
+ procBuf.surfaceFlingerSizeKb,
+ procBuf.surfaceFlingerCount
+ ));
}
return StatsManager.PULL_SUCCESS;
}
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index 53a9244..6adf733d 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -42,8 +42,8 @@
import android.media.tv.interactive.ITvInteractiveAppServiceCallback;
import android.media.tv.interactive.ITvInteractiveAppSession;
import android.media.tv.interactive.ITvInteractiveAppSessionCallback;
-import android.media.tv.interactive.TvInteractiveAppInfo;
import android.media.tv.interactive.TvInteractiveAppService;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -130,7 +130,7 @@
new Intent(TvInteractiveAppService.SERVICE_INTERFACE),
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
userId);
- List<TvInteractiveAppInfo> iAppList = new ArrayList<>();
+ List<TvInteractiveAppServiceInfo> iAppList = new ArrayList<>();
for (ResolveInfo ri : services) {
ServiceInfo si = ri.serviceInfo;
@@ -143,8 +143,8 @@
ComponentName component = new ComponentName(si.packageName, si.name);
try {
- TvInteractiveAppInfo info =
- new TvInteractiveAppInfo(mContext, component);
+ TvInteractiveAppServiceInfo info =
+ new TvInteractiveAppServiceInfo(mContext, component);
iAppList.add(info);
} catch (Exception e) {
Slogf.e(TAG, "failed to load TV Interactive App service " + si.name, e);
@@ -154,10 +154,10 @@
}
// sort the iApp list by iApp service id
- Collections.sort(iAppList, Comparator.comparing(TvInteractiveAppInfo::getId));
+ Collections.sort(iAppList, Comparator.comparing(TvInteractiveAppServiceInfo::getId));
Map<String, TvInteractiveAppState> iAppMap = new HashMap<>();
ArrayMap<String, Integer> tiasAppCount = new ArrayMap<>(iAppMap.size());
- for (TvInteractiveAppInfo info : iAppList) {
+ for (TvInteractiveAppServiceInfo info : iAppList) {
String iAppServiceId = info.getId();
if (DEBUG) {
Slogf.d(TAG, "add " + iAppServiceId);
@@ -195,7 +195,7 @@
for (String iAppServiceId : userState.mIAppMap.keySet()) {
if (!iAppMap.containsKey(iAppServiceId)) {
- TvInteractiveAppInfo info = userState.mIAppMap.get(iAppServiceId).mInfo;
+ TvInteractiveAppServiceInfo info = userState.mIAppMap.get(iAppServiceId).mInfo;
ServiceState serviceState = userState.mServiceStateMap.get(info.getComponent());
if (serviceState != null) {
abortPendingCreateSessionRequestsLocked(serviceState, iAppServiceId, userId);
@@ -283,7 +283,7 @@
userState.mCallbacks.finishBroadcast();
}
- private int getInteractiveAppUid(TvInteractiveAppInfo info) {
+ private int getInteractiveAppUid(TvInteractiveAppServiceInfo info) {
try {
return getContext().getPackageManager().getApplicationInfo(
info.getServiceInfo().packageName, 0).uid;
@@ -642,7 +642,7 @@
private final class BinderService extends ITvInteractiveAppManager.Stub {
@Override
- public List<TvInteractiveAppInfo> getTvInteractiveAppServiceList(int userId) {
+ public List<TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList(int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "getTvInteractiveAppServiceList");
final long identity = Binder.clearCallingIdentity();
@@ -653,7 +653,7 @@
mGetServiceListCalled = true;
}
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
- List<TvInteractiveAppInfo> iAppList = new ArrayList<>();
+ List<TvInteractiveAppServiceInfo> iAppList = new ArrayList<>();
for (TvInteractiveAppState state : userState.mIAppMap.values()) {
iAppList.add(state.mInfo);
}
@@ -1738,7 +1738,7 @@
private static final class TvInteractiveAppState {
private String mIAppServiceId;
private ComponentName mComponentName;
- private TvInteractiveAppInfo mInfo;
+ private TvInteractiveAppServiceInfo mInfo;
private int mUid;
private int mIAppNumber;
}
diff --git a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
index 397acfa..b45c962 100644
--- a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
+++ b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
@@ -88,7 +88,7 @@
@Override
public void traceBegin(@NonNull String name) {
- Slog.i(mTag, name);
+ Slog.d(mTag, name);
super.traceBegin(name);
}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 543e44c..ffc4388 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -746,8 +746,9 @@
// if it is not already expanding to fullscreen. Otherwise, the arguments will
// be used the next time the activity enters PiP.
final Task rootTask = r.getRootTask();
- rootTask.setPictureInPictureAspectRatio(r.pictureInPictureArgs.getAspectRatio(),
- r.pictureInPictureArgs.getExpandedAspectRatio());
+ rootTask.setPictureInPictureAspectRatio(
+ r.pictureInPictureArgs.getAspectRatioFloat(),
+ r.pictureInPictureArgs.getExpandedAspectRatioFloat());
rootTask.setPictureInPictureActions(r.pictureInPictureArgs.getActions());
}
}
@@ -828,7 +829,7 @@
if (params.hasSetAspectRatio()
&& !mService.mWindowManager.isValidPictureInPictureAspectRatio(
- r.mDisplayContent, params.getAspectRatio())) {
+ r.mDisplayContent, params.getAspectRatioFloat())) {
throw new IllegalArgumentException(String.format(caller
+ ": Aspect ratio is too extreme (must be between %f and %f).",
minAspectRatio, maxAspectRatio));
@@ -836,7 +837,7 @@
if (mService.mSupportsExpandedPictureInPicture && params.hasSetExpandedAspectRatio()
&& !mService.mWindowManager.isValidExpandedPictureInPictureAspectRatio(
- r.mDisplayContent, params.getExpandedAspectRatio())) {
+ r.mDisplayContent, params.getExpandedAspectRatioFloat())) {
throw new IllegalArgumentException(String.format(caller
+ ": Expanded aspect ratio is not extreme enough (must not be between"
+ " %f and %f).",
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index c0cdec9..7f84f61 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -191,6 +191,35 @@
private long mCurrentTransitionStartTimeNs;
/** Non-null when a {@link TransitionInfo} is created for this state. */
private TransitionInfo mAssociatedTransitionInfo;
+ /** The sequence id for trace. It is used to map the traces before resolving intent. */
+ private static int sTraceSeqId;
+ /** The trace format is "launchingActivity#$seqId:$state(:$packageName)". */
+ final String mTraceName;
+
+ LaunchingState() {
+ if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ mTraceName = null;
+ return;
+ }
+ // Use an id because the launching app is not yet known before resolving intent.
+ sTraceSeqId++;
+ mTraceName = "launchingActivity#" + sTraceSeqId;
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName, 0);
+ }
+
+ void stopTrace(boolean abort) {
+ if (mTraceName == null) return;
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName, 0);
+ final String launchResult;
+ if (mAssociatedTransitionInfo == null) {
+ launchResult = ":failed";
+ } else {
+ launchResult = (abort ? ":canceled:" : ":completed:")
+ + mAssociatedTransitionInfo.mLastLaunchedActivity.packageName;
+ }
+ // Put a supplement trace as the description of the async trace with the same id.
+ Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName + launchResult);
+ }
@VisibleForTesting
boolean allDrawn() {
@@ -549,10 +578,10 @@
}
if (existingInfo == null) {
- // Only notify the observer for a new launching event.
- launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);
final LaunchingState launchingState = new LaunchingState();
launchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
+ // Only notify the observer for a new launching event.
+ launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);
return launchingState;
}
existingInfo.mLaunchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
@@ -574,7 +603,7 @@
@Nullable ActivityOptions options) {
if (launchedActivity == null) {
// The launch is aborted, e.g. intent not resolved, class not found.
- abort(null /* info */, "nothing launched");
+ abort(launchingState, "nothing launched");
return;
}
@@ -601,7 +630,7 @@
if (launchedActivity.isReportedDrawn() && launchedActivity.isVisible()) {
// Launched activity is already visible. We cannot measure windows drawn delay.
- abort(info, "launched activity already visible");
+ abort(launchingState, "launched activity already visible");
return;
}
@@ -633,7 +662,7 @@
final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState,
options, processRunning, processSwitch, newActivityCreated, resultCode);
if (newInfo == null) {
- abort(info, "unrecognized launch");
+ abort(launchingState, "unrecognized launch");
return;
}
@@ -874,23 +903,29 @@
}
}
+ private void abort(@NonNull LaunchingState state, String cause) {
+ if (state.mAssociatedTransitionInfo != null) {
+ abort(state.mAssociatedTransitionInfo, cause);
+ return;
+ }
+ if (DEBUG_METRICS) Slog.i(TAG, "abort launch cause=" + cause);
+ state.stopTrace(true /* abort */);
+ launchObserverNotifyIntentFailed();
+ }
+
/** Aborts tracking of current launch metrics. */
- private void abort(TransitionInfo info, String cause) {
+ private void abort(@NonNull TransitionInfo info, String cause) {
done(true /* abort */, info, cause, 0L /* timestampNs */);
}
/** Called when the given transition (info) is no longer active. */
- private void done(boolean abort, @Nullable TransitionInfo info, String cause,
+ private void done(boolean abort, @NonNull TransitionInfo info, String cause,
long timestampNs) {
if (DEBUG_METRICS) {
Slog.i(TAG, "done abort=" + abort + " cause=" + cause + " timestamp=" + timestampNs
+ " info=" + info);
}
- if (info == null) {
- launchObserverNotifyIntentFailed();
- return;
- }
-
+ info.mLaunchingState.stopTrace(abort);
stopLaunchTrace(info);
final Boolean isHibernating =
mLastHibernationStates.remove(info.mLastLaunchedActivity.packageName);
@@ -1457,7 +1492,7 @@
/** Starts trace for an activity is actually launching. */
private void startLaunchTrace(@NonNull TransitionInfo info) {
if (DEBUG_METRICS) Slog.i(TAG, "startLaunchTrace " + info);
- if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ if (info.mLaunchingState.mTraceName == null) {
return;
}
info.mLaunchTraceName = "launching: " + info.mLastLaunchedActivity.packageName;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 883ce99..bfe1f30 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5603,19 +5603,8 @@
"makeInvisible", true /* beforeStopping */);
// Defer telling the client it is hidden if it can enter Pip and isn't current paused,
// stopped or stopping. This gives it a chance to enter Pip in onPause().
- // TODO: There is still a question surrounding activities in multi-window mode that want
- // to enter Pip after they are paused, but are still visible. I they should be okay to
- // enter Pip in those cases, but not "auto-Pip" which is what this condition covers and
- // the current contract for "auto-Pip" is that the app should enter it before onPause
- // returns. Just need to confirm this reasoning makes sense.
final boolean deferHidingClient = canEnterPictureInPicture
&& !isState(STARTED, STOPPING, STOPPED, PAUSED);
- if (!mTransitionController.isShellTransitionsEnabled()
- && deferHidingClient && pictureInPictureArgs.isAutoEnterEnabled()) {
- // Go ahead and just put the activity in pip if it supports auto-pip.
- mAtmService.enterPictureInPictureMode(this, pictureInPictureArgs);
- return;
- }
setDeferHidingClient(deferHidingClient);
setVisibility(false);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 7d2dfa0..77ec67f 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2730,10 +2730,11 @@
false /* includingParents */);
intentTask = intentTask.getParent().asTaskFragment().getTask();
}
- // If the task is in multi-windowing mode, the activity may already be on
+ // If the activity is visible in multi-windowing mode, it may already be on
// the top (visible to user but not the global top), then the result code
// should be START_DELIVERED_TO_TOP instead of START_TASK_TO_FRONT.
final boolean wasTopOfVisibleRootTask = intentActivity.mVisibleRequested
+ && intentActivity.inMultiWindowMode()
&& intentActivity == mTargetRootTask.topRunningActivity();
// We only want to move to the front, if we aren't going to launch on a
// different root task. If we launch on a different root task, we will put the
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index b5312c4..988a7c6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3523,8 +3523,9 @@
}
// Only update the saved args from the args that are set
r.setPictureInPictureParams(params);
- final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
- final float expandedAspectRatio = r.pictureInPictureArgs.getExpandedAspectRatio();
+ final float aspectRatio = r.pictureInPictureArgs.getAspectRatioFloat();
+ final float expandedAspectRatio =
+ r.pictureInPictureArgs.getExpandedAspectRatioFloat();
final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
mRootWindowContainer.moveActivityToPinnedRootTask(r,
null /* launchIntoPipHostActivity */, "enterPictureInPictureMode");
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 07a0c37..87523f4 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
+import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONTENT_RECORDING;
@@ -26,6 +27,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
+import android.provider.DeviceConfig;
import android.view.ContentRecordingSession;
import android.view.Display;
import android.view.SurfaceControl;
@@ -39,6 +41,11 @@
final class ContentRecorder {
/**
+ * The key for accessing the device config that controls if task recording is supported.
+ */
+ @VisibleForTesting static final String KEY_RECORD_TASK_FEATURE = "record_task_content";
+
+ /**
* The display content this class is handling recording for.
*/
@NonNull
@@ -48,7 +55,7 @@
* The session for content recording, or null if this DisplayContent is not being used for
* recording.
*/
- @VisibleForTesting private ContentRecordingSession mContentRecordingSession = null;
+ private ContentRecordingSession mContentRecordingSession = null;
/**
* The WindowContainer for the level of the hierarchy to record.
@@ -187,6 +194,8 @@
mDisplayContent.mWmService.mTransactionFactory.get().remove(mRecordedSurface).apply();
mRecordedSurface = null;
clearContentRecordingSession();
+ // Do not need to force remove the VirtualDisplay; this is handled by the media
+ // projection service.
}
}
@@ -215,46 +224,12 @@
return;
}
- final int contentToRecord = mContentRecordingSession.getContentToRecord();
- if (contentToRecord != RECORD_CONTENT_DISPLAY) {
- // TODO(b/216625226) handle task-based recording
- // Not a valid region, or recording is disabled, so fall back to prior MediaProjection
- // approach.
- clearContentRecordingSession();
- ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
- "Unable to start recording due to invalid region for display %d",
- mDisplayContent.getDisplayId());
+ mRecordedWindowContainer = retrieveRecordedWindowContainer();
+ if (mRecordedWindowContainer == null) {
+ // Either the token is missing, or the window associated with the token is missing.
+ // Error has already been handled, so just leave.
return;
}
- // Given the WindowToken of the DisplayArea to record, retrieve the associated
- // SurfaceControl.
- IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
- if (tokenToRecord == null) {
- // Unexpectedly missing token. Fall back to prior MediaProjection approach.
- clearContentRecordingSession();
- ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
- "Unable to start recording due to null token for display %d",
- mDisplayContent.getDisplayId());
- return;
- }
-
- final WindowContainer wc =
- mDisplayContent.mWmService.mWindowContextListenerController.getContainer(
- tokenToRecord);
- if (wc == null) {
- // Un-set the window token to record for this VirtualDisplay. Fall back to the
- // original MediaProjection approach.
- mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring(
- mDisplayContent.getDisplayId(), false);
- clearContentRecordingSession();
- ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
- "Unable to retrieve window container to start recording for "
- + "display %d",
- mDisplayContent.getDisplayId());
- return;
- }
- // TODO(206461622) Migrate to using the RootDisplayArea
- mRecordedWindowContainer = wc.getDisplayContent();
final Point surfaceSize = fetchSurfaceSizeIfPresent();
if (surfaceSize == null) {
@@ -296,6 +271,107 @@
}
/**
+ * Retrieves the {@link WindowContainer} for the level of the hierarchy to start recording,
+ * indicated by the {@link #mContentRecordingSession}. Performs any error handling and state
+ * updates necessary if the {@link WindowContainer} could not be retrieved.
+ * {@link #mContentRecordingSession} must be non-null.
+ *
+ * @return a {@link WindowContainer} to record, or {@code null} if an error was encountered. The
+ * error is logged and any cleanup is handled.
+ */
+ @Nullable
+ private WindowContainer retrieveRecordedWindowContainer() {
+ final int contentToRecord = mContentRecordingSession.getContentToRecord();
+ // Given the WindowToken of the region to record, retrieve the associated
+ // SurfaceControl.
+ final IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
+ if (tokenToRecord == null) {
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to start recording due to null token for display %d",
+ mDisplayContent.getDisplayId());
+ return null;
+ }
+ switch (contentToRecord) {
+ case RECORD_CONTENT_DISPLAY:
+ final WindowContainer wc =
+ mDisplayContent.mWmService.mWindowContextListenerController.getContainer(
+ tokenToRecord);
+ if (wc == null) {
+ // Un-set the window token to record for this VirtualDisplay. Fall back to
+ // Display stack capture for the entire display.
+ mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring(
+ mDisplayContent.getDisplayId(), false);
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to retrieve window container to start recording for "
+ + "display %d", mDisplayContent.getDisplayId());
+ return null;
+ }
+ // TODO(206461622) Migrate to using the RootDisplayArea
+ return wc.getDisplayContent();
+ case RECORD_CONTENT_TASK:
+ if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_RECORD_TASK_FEATURE, false)) {
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to record task since feature is disabled %d",
+ mDisplayContent.getDisplayId());
+ return null;
+ }
+ Task taskToRecord = WindowContainer.fromBinder(tokenToRecord).asTask();
+ if (taskToRecord == null) {
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to retrieve task to start recording for "
+ + "display %d", mDisplayContent.getDisplayId());
+ }
+ return taskToRecord;
+ default:
+ // Not a valid region, or recording is disabled, so fall back to Display stack
+ // capture for the entire display.
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to start recording due to invalid region for display %d",
+ mDisplayContent.getDisplayId());
+ return null;
+ }
+ }
+
+ /**
+ * Exit this recording session.
+ * <p>
+ * If this is a task session, tear down the recording entirely. Do not fall back
+ * to recording the entire display on the display stack; this would surprise the user
+ * given they selected task capture.
+ * </p><p>
+ * If this is a display session, just stop recording by layer mirroring. Fall back to recording
+ * from the display stack.
+ * </p>
+ */
+ private void handleStartRecordingFailed() {
+ final boolean shouldExitTaskRecording = mContentRecordingSession != null
+ && mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK;
+ if (shouldExitTaskRecording) {
+ // Clean up the cached session first, since tearing down the display will generate
+ // display
+ // events which will trickle back to here.
+ clearContentRecordingSession();
+ tearDownVirtualDisplay();
+ } else {
+ clearContentRecordingSession();
+ }
+ }
+
+ /**
+ * Ensure recording does not fall back to the display stack; ensure the recording is stopped
+ * and the client notified by tearing down the virtual display.
+ */
+ private void tearDownVirtualDisplay() {
+ // TODO(b/219761722) Clean up the VirtualDisplay if task mirroring fails
+ }
+
+ /**
* Apply transformations to the mirrored surface to ensure the captured contents are scaled to
* fit and centred in the output surface.
*
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 597d29f..2ac41a7 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -63,8 +63,6 @@
import static com.android.server.wm.TaskFragmentProto.MIN_HEIGHT;
import static com.android.server.wm.TaskFragmentProto.MIN_WIDTH;
import static com.android.server.wm.TaskFragmentProto.WINDOW_CONTAINER;
-import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
-import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.TASK_FRAGMENT;
import android.annotation.IntDef;
@@ -1461,7 +1459,8 @@
// next activity.
final boolean lastResumedCanPip = prev.checkEnterPictureInPictureState(
"shouldAutoPipWhilePausing", userLeaving);
- if (lastResumedCanPip && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
+ if (userLeaving && lastResumedCanPip
+ && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
shouldAutoPip = true;
} else if (!lastResumedCanPip) {
// If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
@@ -2370,8 +2369,7 @@
if (!hasChild()) {
return false;
}
- return isAnimating(TRANSITION | CHILDREN, WindowState.EXIT_ANIMATING_TYPES)
- || inTransition();
+ return isExitAnimationRunningSelfOrChild() || inTransition();
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index dab02de..e7b4e83 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1196,6 +1196,23 @@
return false;
}
+ boolean isExitAnimationRunningSelfOrChild() {
+ if (!mTransitionController.isShellTransitionsEnabled()) {
+ return isAnimating(TRANSITION | CHILDREN, WindowState.EXIT_ANIMATING_TYPES);
+ }
+ if (mTransitionController.isCollecting(this)) {
+ return true;
+ }
+
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ WindowContainer child = mChildren.get(i);
+ if (child.isExitAnimationRunningSelfOrChild()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
void sendAppVisibilityToClients() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d5f7a22..eb88b8b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -119,7 +119,6 @@
import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
-import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
@@ -2503,8 +2502,6 @@
ProtoLog.v(WM_DEBUG_FOCUS, "Relayout of %s: focusMayChange=%b",
win, focusMayChange);
- result |= mInTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
-
if (DEBUG_LAYOUT) {
Slog.v(TAG_WM, "Relayout complete " + win + ": outFrames=" + outFrames);
}
@@ -2563,8 +2560,7 @@
if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
focusMayChange = true;
win.mAnimatingExit = true;
- } else if (win.mDisplayContent.okToAnimate() && win.isAnimating(TRANSITION | PARENTS,
- WindowState.EXIT_ANIMATING_TYPES)) {
+ } else if (win.mDisplayContent.okToAnimate() && win.isExitAnimationRunningSelfOrParent()) {
// Currently in a hide animation... turn this into
// an exit.
win.mAnimatingExit = true;
@@ -3282,7 +3278,7 @@
mContext.enforceCallingOrSelfPermission(
Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE,
Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE
- + " permission required to read keyguard visibility");
+ + " permission required to subscribe to keyguard locked state changes");
}
private void dispatchKeyguardLockedState() {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f667392..60e196c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -134,6 +134,7 @@
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_STARTING_REVEAL;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.WINDOW;
@@ -2610,8 +2611,7 @@
mWmService.mAccessibilityController.onWindowTransition(this, transit);
}
}
- final boolean isAnimating = mAnimatingExit
- || isAnimating(TRANSITION | PARENTS, EXIT_ANIMATING_TYPES);
+ final boolean isAnimating = mAnimatingExit || isExitAnimationRunningSelfOrParent();
final boolean lastWindowIsStartingWindow = startingWindow && mActivityRecord != null
&& mActivityRecord.isLastWindow(this);
// We delay the removal of a window if it has a showing surface that can be used to run
@@ -4977,6 +4977,15 @@
return false;
}
+ boolean isExitAnimationRunningSelfOrParent() {
+ return inAppOrRecentsTransition()
+ || isAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION);
+ }
+
+ boolean isExitAnimationRunningSelfOrChild() {
+ return isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION);
+ }
+
private boolean shouldFinishAnimatingExit() {
// Exit animation might be applied soon.
if (inTransition()) {
@@ -4988,7 +4997,7 @@
return true;
}
// Exit animation is running.
- if (isAnimating(TRANSITION | PARENTS, EXIT_ANIMATING_TYPES)) {
+ if (isExitAnimationRunningSelfOrParent()) {
ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "shouldWaitAnimatingExit: isAnimating: %s",
this);
return false;
@@ -5081,7 +5090,7 @@
@Override
boolean handleCompleteDeferredRemoval() {
- if (mRemoveOnExit && !isSelfAnimating(0 /* flags */, EXIT_ANIMATING_TYPES)) {
+ if (mRemoveOnExit && !isSelfAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION)) {
mRemoveOnExit = false;
removeImmediately();
}
diff --git a/services/core/jni/gnss/MeasurementCorrections.cpp b/services/core/jni/gnss/MeasurementCorrections.cpp
index 8a3d84c..07d0a45 100644
--- a/services/core/jni/gnss/MeasurementCorrections.cpp
+++ b/services/core/jni/gnss/MeasurementCorrections.cpp
@@ -44,6 +44,7 @@
using ReflectingPlane_V1_0 =
android::hardware::gnss::measurement_corrections::V1_0::ReflectingPlane;
using ReflectingPlane_Aidl = android::hardware::gnss::measurement_corrections::ReflectingPlane;
+using ExcessPathInfo = SingleSatCorrection_Aidl::ExcessPathInfo;
using GnssConstellationType_V1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
using GnssConstellationType_V2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
using GnssConstellationType_Aidl = android::hardware::gnss::GnssConstellationType;
@@ -62,7 +63,7 @@
jmethodID method_correctionsGetEnvironmentBearingDegrees;
jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
jmethodID method_listSize;
-jmethodID method_correctionListGet;
+jmethodID method_listGet;
jmethodID method_correctionSatFlags;
jmethodID method_correctionSatConstType;
jmethodID method_correctionSatId;
@@ -71,10 +72,17 @@
jmethodID method_correctionSatEpl;
jmethodID method_correctionSatEplUnc;
jmethodID method_correctionSatRefPlane;
+jmethodID method_correctionSatAttenuation;
+jmethodID method_correctionSatExcessPathInfoList;
jmethodID method_correctionPlaneLatDeg;
jmethodID method_correctionPlaneLngDeg;
jmethodID method_correctionPlaneAltDeg;
jmethodID method_correctionPlaneAzimDeg;
+jmethodID method_excessPathInfoFlags;
+jmethodID method_excessPathInfoEpl;
+jmethodID method_excessPathInfoEplUnc;
+jmethodID method_excessPathInfoRefPlane;
+jmethodID method_excessPathInfoAttenuation;
} // anonymous namespace
void MeasurementCorrections_class_init_once(JNIEnv* env, jclass clazz) {
@@ -103,7 +111,7 @@
jclass corrListClass = env->FindClass("java/util/List");
method_listSize = env->GetMethodID(corrListClass, "size", "()I");
- method_correctionListGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;");
+ method_listGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;");
jclass singleSatCorrClass = env->FindClass("android/location/GnssSingleSatCorrection");
method_correctionSatFlags =
@@ -121,12 +129,27 @@
env->GetMethodID(singleSatCorrClass, "getExcessPathLengthUncertaintyMeters", "()F");
method_correctionSatRefPlane = env->GetMethodID(singleSatCorrClass, "getReflectingPlane",
"()Landroid/location/GnssReflectingPlane;");
+ method_correctionSatAttenuation =
+ env->GetMethodID(singleSatCorrClass, "getCombinedAttenuationDb", "()F");
+ method_correctionSatExcessPathInfoList =
+ env->GetMethodID(singleSatCorrClass, "getGnssExcessPathInfoList", "()Ljava/util/List;");
jclass refPlaneClass = env->FindClass("android/location/GnssReflectingPlane");
method_correctionPlaneLatDeg = env->GetMethodID(refPlaneClass, "getLatitudeDegrees", "()D");
method_correctionPlaneLngDeg = env->GetMethodID(refPlaneClass, "getLongitudeDegrees", "()D");
method_correctionPlaneAltDeg = env->GetMethodID(refPlaneClass, "getAltitudeMeters", "()D");
method_correctionPlaneAzimDeg = env->GetMethodID(refPlaneClass, "getAzimuthDegrees", "()D");
+
+ jclass excessPathInfoClass = env->FindClass("android/location/GnssExcessPathInfo");
+ method_excessPathInfoFlags = env->GetMethodID(excessPathInfoClass, "getFlags", "()I");
+ method_excessPathInfoEpl =
+ env->GetMethodID(excessPathInfoClass, "getExcessPathLengthMeters", "()F");
+ method_excessPathInfoEplUnc =
+ env->GetMethodID(excessPathInfoClass, "getExcessPathLengthUncertaintyMeters", "()F");
+ method_excessPathInfoRefPlane = env->GetMethodID(excessPathInfoClass, "getReflectingPlane",
+ "()Landroid/location/GnssReflectingPlane;");
+ method_excessPathInfoAttenuation =
+ env->GetMethodID(excessPathInfoClass, "getAttenuationDb", "()F");
}
template <>
@@ -324,7 +347,8 @@
SingleSatCorrection_V1_0
MeasurementCorrectionsUtil::getSingleSatCorrection_1_0_withoutConstellation(
JNIEnv* env, jobject singleSatCorrectionObj) {
- jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+ uint16_t corrFlags = static_cast<uint16_t>(
+ env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags));
jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
jfloat carrierFreqHz =
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
@@ -332,14 +356,16 @@
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
- uint16_t corrFlags = static_cast<uint16_t>(correctionFlags);
ReflectingPlane_V1_0 reflectingPlane;
- if ((corrFlags & GnssSingleSatCorrectionFlags_V1_0::HAS_REFLECTING_PLANE) != 0)
- MeasurementCorrectionsUtil::getReflectingPlane<ReflectingPlane_V1_0>(env,
- singleSatCorrectionObj,
+ if ((corrFlags & GnssSingleSatCorrectionFlags_V1_0::HAS_REFLECTING_PLANE) != 0) {
+ jobject reflectingPlaneObj =
+ env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
+ MeasurementCorrectionsUtil::setReflectingPlane<ReflectingPlane_V1_0>(env,
+ reflectingPlaneObj,
reflectingPlane);
-
+ env->DeleteLocalRef(reflectingPlaneObj);
+ }
SingleSatCorrection_V1_0 singleSatCorrection = {
.singleSatCorrectionFlags = corrFlags,
.svid = static_cast<uint16_t>(satId),
@@ -349,13 +375,14 @@
.excessPathLengthUncertaintyMeters = eplUncMeters,
.reflectingPlane = reflectingPlane,
};
-
return singleSatCorrection;
}
SingleSatCorrection_Aidl MeasurementCorrectionsUtil::getSingleSatCorrection_Aidl(
JNIEnv* env, jobject singleSatCorrectionObj) {
- jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+ int32_t corrFlags = static_cast<int32_t>(
+ env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags));
+ jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
jfloat carrierFreqHz =
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
@@ -363,15 +390,10 @@
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
- int32_t corrFlags = static_cast<int32_t>(correctionFlags);
-
- ReflectingPlane_Aidl reflectingPlane;
- if ((corrFlags & SingleSatCorrection_Aidl::SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE) != 0)
- MeasurementCorrectionsUtil::getReflectingPlane<ReflectingPlane_Aidl>(env,
- singleSatCorrectionObj,
- reflectingPlane);
-
- jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
+ jfloat attenuationDb =
+ env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatAttenuation);
+ std::vector<ExcessPathInfo> excessPathInfos =
+ MeasurementCorrectionsUtil::getExcessPathInfoList(env, singleSatCorrectionObj);
SingleSatCorrection_Aidl singleSatCorrection;
singleSatCorrection.singleSatCorrectionFlags = corrFlags;
@@ -379,9 +401,10 @@
singleSatCorrection.svid = static_cast<int32_t>(satId);
singleSatCorrection.carrierFrequencyHz = carrierFreqHz;
singleSatCorrection.probSatIsLos = probSatIsLos;
- singleSatCorrection.excessPathLengthMeters = eplMeters;
- singleSatCorrection.excessPathLengthUncertaintyMeters = eplUncMeters;
- singleSatCorrection.reflectingPlane = reflectingPlane;
+ singleSatCorrection.combinedExcessPathLengthMeters = eplMeters;
+ singleSatCorrection.combinedExcessPathLengthUncertaintyMeters = eplUncMeters;
+ singleSatCorrection.combinedAttenuationDb = attenuationDb;
+ singleSatCorrection.excessPathInfos = excessPathInfos;
return singleSatCorrection;
}
@@ -391,8 +414,7 @@
hardware::hidl_vec<SingleSatCorrection_V1_0>& list) {
for (uint16_t i = 0; i < list.size(); ++i) {
jobject singleSatCorrectionObj =
- env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
-
+ env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
SingleSatCorrection_V1_0 singleSatCorrection =
getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
@@ -410,7 +432,7 @@
hardware::hidl_vec<SingleSatCorrection_V1_1>& list) {
for (uint16_t i = 0; i < list.size(); ++i) {
jobject singleSatCorrectionObj =
- env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+ env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
SingleSatCorrection_V1_0 singleSatCorrection_1_0 =
getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
@@ -431,7 +453,7 @@
JNIEnv* env, jobject singleSatCorrectionList, std::vector<SingleSatCorrection_Aidl>& list) {
for (uint16_t i = 0; i < list.size(); ++i) {
jobject singleSatCorrectionObj =
- env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+ env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
SingleSatCorrection_Aidl singleSatCorrection_Aidl =
getSingleSatCorrection_Aidl(env, singleSatCorrectionObj);
@@ -441,4 +463,63 @@
}
}
+template <>
+void MeasurementCorrectionsUtil::setReflectingPlaneAzimuthDegrees<ReflectingPlane_V1_0>(
+ ReflectingPlane_V1_0& reflectingPlane, double azimuthDegreeRefPlane) {
+ reflectingPlane.azimuthDegrees = azimuthDegreeRefPlane;
+}
+
+template <>
+void MeasurementCorrectionsUtil::setReflectingPlaneAzimuthDegrees<ReflectingPlane_Aidl>(
+ ReflectingPlane_Aidl& reflectingPlane, double azimuthDegreeRefPlane) {
+ reflectingPlane.reflectingPlaneAzimuthDegrees = azimuthDegreeRefPlane;
+}
+
+std::vector<ExcessPathInfo> MeasurementCorrectionsUtil::getExcessPathInfoList(
+ JNIEnv* env, jobject singleSatCorrectionObj) {
+ jobject excessPathInfoListObj =
+ env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatExcessPathInfoList);
+
+ int len = env->CallIntMethod(excessPathInfoListObj, method_listSize);
+ std::vector<ExcessPathInfo> list(len);
+ for (int i = 0; i < len; ++i) {
+ jobject excessPathInfoObj = env->CallObjectMethod(excessPathInfoListObj, method_listGet, i);
+ list[i] = getExcessPathInfo(env, excessPathInfoObj);
+ env->DeleteLocalRef(excessPathInfoObj);
+ }
+ env->DeleteLocalRef(excessPathInfoListObj);
+ return list;
+}
+
+ExcessPathInfo MeasurementCorrectionsUtil::getExcessPathInfo(JNIEnv* env,
+ jobject excessPathInfoObj) {
+ ExcessPathInfo excessPathInfo;
+ jint flags = env->CallIntMethod(excessPathInfoObj, method_excessPathInfoFlags);
+ excessPathInfo.excessPathInfoFlags = flags;
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH) != 0) {
+ jfloat epl = env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoEpl);
+ excessPathInfo.excessPathLengthMeters = epl;
+ }
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC) != 0) {
+ jfloat eplUnc = env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoEplUnc);
+ excessPathInfo.excessPathLengthUncertaintyMeters = eplUnc;
+ }
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_REFLECTING_PLANE) != 0) {
+ ReflectingPlane_Aidl reflectingPlane;
+ jobject reflectingPlaneObj =
+ env->CallObjectMethod(excessPathInfoObj, method_excessPathInfoRefPlane);
+ MeasurementCorrectionsUtil::setReflectingPlane<ReflectingPlane_Aidl>(env,
+ reflectingPlaneObj,
+ reflectingPlane);
+ env->DeleteLocalRef(reflectingPlaneObj);
+ excessPathInfo.reflectingPlane = reflectingPlane;
+ }
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_ATTENUATION) != 0) {
+ jfloat attenuation =
+ env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoAttenuation);
+ excessPathInfo.attenuationDb = attenuation;
+ }
+ return excessPathInfo;
+}
+
} // namespace android::gnss
diff --git a/services/core/jni/gnss/MeasurementCorrections.h b/services/core/jni/gnss/MeasurementCorrections.h
index a2e6027..598ad48 100644
--- a/services/core/jni/gnss/MeasurementCorrections.h
+++ b/services/core/jni/gnss/MeasurementCorrections.h
@@ -43,7 +43,7 @@
extern jmethodID method_correctionsGetEnvironmentBearingDegrees;
extern jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
extern jmethodID method_listSize;
-extern jmethodID method_correctionListGet;
+extern jmethodID method_listGet;
extern jmethodID method_correctionSatFlags;
extern jmethodID method_correctionSatConstType;
extern jmethodID method_correctionSatId;
@@ -52,6 +52,7 @@
extern jmethodID method_correctionSatEpl;
extern jmethodID method_correctionSatEplUnc;
extern jmethodID method_correctionSatRefPlane;
+extern jmethodID method_correctionSatExcessPathInfos;
extern jmethodID method_correctionPlaneLatDeg;
extern jmethodID method_correctionPlaneLngDeg;
extern jmethodID method_correctionPlaneAltDeg;
@@ -130,14 +131,20 @@
static bool translateMeasurementCorrections(JNIEnv* env, jobject correctionsObj,
T& corrections);
template <class T>
- static void getReflectingPlane(JNIEnv* env, jobject singleSatCorrectionObj, T& reflectingPlane);
+ static void setReflectingPlane(JNIEnv* env, jobject reflectingPlaneObj, T& reflectingPlane);
+ template <class T>
+ static void setReflectingPlaneAzimuthDegrees(T& reflectingPlane, double azimuthDegreeRefPlane);
+
+ static std::vector<
+ android::hardware::gnss::measurement_corrections::SingleSatCorrection::ExcessPathInfo>
+ getExcessPathInfoList(JNIEnv* env, jobject correctionsObj);
+ static android::hardware::gnss::measurement_corrections::SingleSatCorrection::ExcessPathInfo
+ getExcessPathInfo(JNIEnv* env, jobject correctionsObj);
};
template <class T>
-void MeasurementCorrectionsUtil::getReflectingPlane(JNIEnv* env, jobject singleSatCorrectionObj,
+void MeasurementCorrectionsUtil::setReflectingPlane(JNIEnv* env, jobject reflectingPlaneObj,
T& reflectingPlane) {
- jobject reflectingPlaneObj =
- env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
jdouble latitudeDegreesRefPlane =
env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLatDeg);
jdouble longitudeDegreesRefPlane =
@@ -149,8 +156,7 @@
reflectingPlane.latitudeDegrees = latitudeDegreesRefPlane;
reflectingPlane.longitudeDegrees = longitudeDegreesRefPlane;
reflectingPlane.altitudeMeters = altitudeDegreesRefPlane;
- reflectingPlane.azimuthDegrees = azimuthDegreeRefPlane;
- env->DeleteLocalRef(reflectingPlaneObj);
+ setReflectingPlaneAzimuthDegrees<T>(reflectingPlane, azimuthDegreeRefPlane);
}
} // namespace android::gnss
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 2f5ab0b..48c4052 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -1227,5 +1227,12 @@
pw.print("mSsidDenylist=");
pw.println(mSsidDenylist);
+
+ if (mFactoryResetProtectionPolicy != null) {
+ pw.println("mFactoryResetProtectionPolicy:");
+ pw.increaseIndent();
+ mFactoryResetProtectionPolicy.dump(pw);
+ pw.decreaseIndent();
+ }
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 200b120..ba00bee 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -189,4 +189,9 @@
public ParcelableResource getString(String stringId) {
return null;
}
+
+ @Override
+ public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
+ return false;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3d40f48..850fdee 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -18384,14 +18384,8 @@
} else {
preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT);
}
- List<Integer> allowedUids = Arrays.stream(
- preferentialNetworkServiceConfig.getIncludedUids()).boxed().collect(
- Collectors.toList());
- List<Integer> excludedUids = Arrays.stream(
- preferentialNetworkServiceConfig.getExcludedUids()).boxed().collect(
- Collectors.toList());
- preferenceBuilder.setIncludedUids(allowedUids);
- preferenceBuilder.setExcludedUids(excludedUids);
+ preferenceBuilder.setIncludedUids(preferentialNetworkServiceConfig.getIncludedUids());
+ preferenceBuilder.setExcludedUids(preferentialNetworkServiceConfig.getExcludedUids());
preferenceBuilder.setPreferenceEnterpriseId(
preferentialNetworkServiceConfig.getNetworkId());
@@ -18790,4 +18784,18 @@
mInjector.binderWithCleanCallingIdentity(() -> Settings.Secure.putInt(
mContext.getContentResolver(), MANAGED_PROVISIONING_DPC_DOWNLOADED, setTo));
}
+
+ @Override
+ public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_ROLE_HOLDERS));
+ return mInjector.binderWithCleanCallingIdentity(() -> {
+ if (mUserManager.getUserCount() > 1) {
+ return false;
+ }
+ AccountManager am = AccountManager.get(mContext);
+ Account[] accounts = am.getAccounts();
+ return accounts.length == 0;
+ });
+ }
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 8f81e93..7a9c412 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -143,6 +143,7 @@
AndroidPackage::getLogo,
AndroidPackage::getLocaleConfigRes,
AndroidPackage::getManageSpaceActivityName,
+ AndroidPackage::getMaxSdkVersion,
AndroidPackage::getMemtagMode,
AndroidPackage::getMinSdkVersion,
AndroidPackage::getNativeHeapZeroInitialized,
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 784f732..8d6269c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -118,6 +118,7 @@
LocalServices.removeServiceForTest(LightsManager.class);
LocalServices.addService(LightsManager.class, mMockedLightsManager);
mInjector = new Injector();
+ when(mSurfaceControlProxy.getBootDisplayModeSupport()).thenReturn(true);
mAdapter = new LocalDisplayAdapter(mMockedSyncRoot, mMockedContext, mHandler,
mListener, mInjector);
spyOn(mAdapter);
@@ -904,7 +905,6 @@
.thenReturn(display.dynamicInfo);
when(mSurfaceControlProxy.getDesiredDisplayModeSpecs(display.token))
.thenReturn(display.desiredDisplayModeSpecs);
- when(mSurfaceControlProxy.getBootDisplayModeSupport()).thenReturn(true);
}
private void updateAvailableDisplays() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
index 6f503c7..444db91 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
@@ -19,7 +19,9 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
@@ -36,23 +38,21 @@
import android.content.IntentFilter;
import android.os.HandlerThread;
import android.os.PowerManager;
-import android.util.ArraySet;
import com.android.server.LocalServices;
import com.android.server.PinnerService;
import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.dex.DexoptOptions;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
@@ -66,9 +66,8 @@
private static final long TEST_WAIT_TIMEOUT_MS = 10_000;
- private static final ArraySet<String> DEFAULT_PACKAGE_LIST = new ArraySet<>(
- Arrays.asList("aaa", "bbb"));
- private static final ArraySet<String> EMPTY_PACKAGE_LIST = new ArraySet<>();
+ private static final List<String> DEFAULT_PACKAGE_LIST = List.of("aaa", "bbb");
+ private static final List<String> EMPTY_PACKAGE_LIST = List.of();
@Mock
private Context mContext;
@@ -116,9 +115,11 @@
when(mInjector.getDataDirStorageLowBytes()).thenReturn(STORAGE_LOW_BYTES);
when(mInjector.getDexOptThermalCutoff()).thenReturn(PowerManager.THERMAL_STATUS_CRITICAL);
when(mInjector.getCurrentThermalStatus()).thenReturn(PowerManager.THERMAL_STATUS_NONE);
+ when(mInjector.supportSecondaryDex()).thenReturn(true);
when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(DEFAULT_PACKAGE_LIST);
when(mDexOptHelper.performDexOptWithStatus(any())).thenReturn(
PackageDexOptimizer.DEX_OPT_PERFORMED);
+ when(mDexOptHelper.performDexOpt(any())).thenReturn(true);
mService = new BackgroundDexOptService(mInjector);
}
@@ -418,26 +419,16 @@
verifyPerformDexOpt(DEFAULT_PACKAGE_LIST, totalJobRuns);
}
- private void verifyPerformDexOpt(ArraySet<String> pkgs, int expectedRuns) {
- ArgumentCaptor<DexoptOptions> dexOptOptions = ArgumentCaptor.forClass(DexoptOptions.class);
- verify(mDexOptHelper, atLeastOnce()).performDexOptWithStatus(dexOptOptions.capture());
- HashMap<String, Integer> primaryPkgs = new HashMap<>(); // K: pkg, V: dexopt runs left
- for (String pkg : pkgs) {
- primaryPkgs.put(pkg, expectedRuns);
- }
-
- for (DexoptOptions opt : dexOptOptions.getAllValues()) {
- assertThat(pkgs).contains(opt.getPackageName());
- assertThat(opt.isDexoptOnlySecondaryDex()).isFalse();
- Integer count = primaryPkgs.get(opt.getPackageName());
- assertThat(count).isNotNull();
- if (count == 1) {
- primaryPkgs.remove(opt.getPackageName());
- } else {
- primaryPkgs.put(opt.getPackageName(), count - 1);
+ private void verifyPerformDexOpt(List<String> pkgs, int expectedRuns) {
+ InOrder inOrder = inOrder(mDexOptHelper);
+ for (int i = 0; i < expectedRuns; i++) {
+ for (String pkg : pkgs) {
+ inOrder.verify(mDexOptHelper, times(1)).performDexOptWithStatus(argThat((option) ->
+ option.getPackageName().equals(pkg) && !option.isDexoptOnlySecondaryDex()));
+ inOrder.verify(mDexOptHelper, times(1)).performDexOpt(argThat((option) ->
+ option.getPackageName().equals(pkg) && option.isDexoptOnlySecondaryDex()));
}
}
- assertThat(primaryPkgs).isEmpty();
}
private static class StartAndWaitThread extends Thread {
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java
new file mode 100644
index 0000000..52cd29c
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.utils;
+
+import static android.os.Trace.TRACE_TAG_APP;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.contains;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.matches;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+
+import android.os.Trace;
+import android.util.Slog;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.MockedVoidMethod;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link TimingsTraceAndSlog}.
+ *
+ * <p>Usage: {@code atest FrameworksMockingServicesTests:TimingsTraceAndSlogTest}
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TimingsTraceAndSlogTest {
+
+ private static final String TAG = "TEST";
+
+ private MockitoSession mSession;
+
+ @Before
+ public final void startMockSession() {
+ mSession = mockitoSession()
+ .spyStatic(Slog.class)
+ .spyStatic(Trace.class)
+ .startMocking();
+ }
+
+ @After
+ public final void finishMockSession() {
+ mSession.finishMocking();
+ }
+
+ @Test
+ public void testDifferentThreads() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ // Should be able to log on the same thread
+ log.traceBegin("test");
+ log.traceEnd();
+ final List<String> errors = new ArrayList<>();
+ // Calling from a different thread should fail
+ Thread t = new Thread(() -> {
+ try {
+ log.traceBegin("test");
+ errors.add("traceBegin should fail on a different thread");
+ } catch (IllegalStateException expected) {
+ }
+ try {
+ log.traceEnd();
+ errors.add("traceEnd should fail on a different thread");
+ } catch (IllegalStateException expected) {
+ }
+ // Verify that creating a new log will work
+ TimingsTraceAndSlog log2 = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log2.traceBegin("test");
+ log2.traceEnd();
+
+ });
+ t.start();
+ t.join();
+ assertThat(errors).isEmpty();
+ }
+
+ @Test
+ public void testGetUnfinishedTracesForDebug() {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
+
+ log.traceBegin("One");
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
+
+ log.traceBegin("Two");
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One", "Two").inOrder();
+
+ log.traceEnd();
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
+
+ log.traceEnd();
+ assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
+ }
+
+ @Test
+ public void testLogDuration() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.logDuration("logro", 42);
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), contains("logro took to complete: 42ms")));
+ }
+
+ @Test
+ public void testOneLevel() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.traceBegin("test");
+ log.traceEnd();
+
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "test"));
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("test took to complete: \\dms")));
+ }
+
+ @Test
+ public void testMultipleLevels() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.traceBegin("L1");
+ log.traceBegin("L2");
+ log.traceEnd();
+ log.traceEnd();
+
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L1"));
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L2"));
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(2)); // L1 and L2
+
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
+ }
+
+ @Test
+ public void testEndNoBegin() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.traceEnd();
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
+ verify((MockedVoidMethod) () -> Slog.d(eq(TAG), anyString()), never());
+ verify((MockedVoidMethod) () -> Slog.w(TAG, "traceEnd called more times than traceBegin"));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index f3a0b7f..0780d21 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -28,6 +28,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -45,13 +46,16 @@
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.display.DisplayManagerInternal;
import android.os.Looper;
+import android.view.DisplayInfo;
import android.view.MagnificationSpec;
import android.view.accessibility.MagnificationAnimationCallback;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityTraceManager;
import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.wm.WindowManagerInternal;
@@ -113,6 +117,8 @@
FullScreenMagnificationController mFullScreenMagnificationController;
+ public DisplayManagerInternal mDisplayManagerInternalMock = mock(DisplayManagerInternal.class);
+
@Before
public void setUp() {
Looper looper = InstrumentationRegistry.getContext().getMainLooper();
@@ -125,6 +131,12 @@
when(mMockControllerCtx.getAnimationDuration()).thenReturn(1000L);
initMockWindowManager();
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.logicalDensityDpi = 300;
+ doReturn(displayInfo).when(mDisplayManagerInternalMock).getDisplayInfo(anyInt());
+ LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+ LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
+
mFullScreenMagnificationController = new FullScreenMagnificationController(
mMockControllerCtx, new Object(), mRequestObserver, mScaleProvider);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 1ebcbe1..8438afcf 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4260,14 +4260,11 @@
dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
.isEnabled()).isTrue();
- List<Integer> includedList = new ArrayList<>();
- includedList.add(1);
- includedList.add(2);
ProfileNetworkPreference preferenceDetails =
new ProfileNetworkPreference.Builder()
.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK)
.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
- .setIncludedUids(includedList)
+ .setIncludedUids(new int[]{1, 2})
.build();
List<ProfileNetworkPreference> preferences = new ArrayList<>();
preferences.add(preferenceDetails);
@@ -4295,14 +4292,11 @@
dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
.isEnabled()).isTrue();
- List<Integer> excludedUids = new ArrayList<>();
- excludedUids.add(1);
- excludedUids.add(2);
ProfileNetworkPreference preferenceDetails =
new ProfileNetworkPreference.Builder()
.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK)
.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
- .setExcludedUids(excludedUids)
+ .setExcludedUids(new int[]{1, 2})
.build();
List<ProfileNetworkPreference> preferences = new ArrayList<>();
preferences.clear();
diff --git a/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java b/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java
new file mode 100644
index 0000000..26a83a2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.display.DisplayManagerInternal;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+
+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;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ColorFadeTest {
+ private static final int DISPLAY_ID = 123;
+
+ private Context mContext;
+
+ @Mock private DisplayManagerInternal mDisplayManagerInternalMock;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock);
+ mContext = getInstrumentation().getTargetContext();
+ }
+
+ @After
+ public void tearDown() {
+ LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+ }
+
+ @Test
+ public void testPrepareColorFadeForInvalidDisplay() {
+ when(mDisplayManagerInternalMock.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(null);
+ ColorFade colorFade = new ColorFade(DISPLAY_ID);
+ assertFalse(colorFade.prepare(mContext, ColorFade.MODE_FADE));
+ }
+
+ private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+ LocalServices.removeServiceForTest(clazz);
+ LocalServices.addService(clazz, mock);
+ }
+
+}
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 31be33e..fd1536c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -43,6 +43,7 @@
import static com.android.os.AtomsProto.DNDModeProto.ID_FIELD_NUMBER;
import static com.android.os.AtomsProto.DNDModeProto.UID_FIELD_NUMBER;
import static com.android.os.AtomsProto.DNDModeProto.ZEN_MODE_FIELD_NUMBER;
+import static com.android.server.notification.ZenModeHelper.RULE_LIMIT_PER_PACKAGE;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -1611,6 +1612,35 @@
}
@Test
+ public void testAddAutomaticZenRule_beyondSystemLimit() {
+ for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) {
+ ScheduleInfo si = new ScheduleInfo();
+ si.startHour = i;
+ AutomaticZenRule zenRule = new AutomaticZenRule("name" + i,
+ null,
+ new ComponentName("android", "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(si),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test");
+ assertNotNull(id);
+ }
+ try {
+ 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");
+ fail("allowed too many rules to be created");
+ } catch (IllegalArgumentException e) {
+ // yay
+ }
+
+ }
+
+ @Test
public void testAddAutomaticZenRule_CA() {
AutomaticZenRule zenRule = new AutomaticZenRule("name",
null,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index f9aa4b1..9902e83 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -500,6 +500,23 @@
return Pair.create(splitPrimaryActivity, splitSecondActivity);
}
+ @Test
+ public void testMoveVisibleTaskToFront() {
+ final ActivityRecord activity = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true).build().getTopMostActivity();
+ final ActivityRecord translucentActivity = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true).build().getTopMostActivity();
+ assertTrue(activity.mVisibleRequested);
+
+ final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
+ false /* mockGetRootTask */);
+ starter.getIntent().setComponent(activity.mActivityComponent);
+ final int result = starter.setReason("testMoveVisibleTaskToFront").execute();
+
+ assertEquals(START_TASK_TO_FRONT, result);
+ assertEquals(1, activity.compareTo(translucentActivity));
+ }
+
/**
* Tests activity is cleaned up properly in a task mode violation.
*/
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index 50eefa0..c5117bb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -19,12 +19,12 @@
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
-import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ContentRecorder.KEY_RECORD_TASK_FEATURE;
import static com.google.common.truth.Truth.assertThat;
@@ -40,17 +40,22 @@
import android.os.Binder;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
import android.util.DisplayMetrics;
import android.view.ContentRecordingSession;
import android.view.Surface;
import android.view.SurfaceControl;
+import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.CountDownLatch;
+
/**
* Tests for the {@link ContentRecorder} class.
*
@@ -62,17 +67,18 @@
@RunWith(WindowTestRunner.class)
public class ContentRecorderTests extends WindowTestsBase {
private static final IBinder TEST_TOKEN = new RecordingTestToken();
- private final ContentRecordingSession mDefaultSession =
+ private static IBinder sTaskWindowContainerToken;
+ private final ContentRecordingSession mDisplaySession =
ContentRecordingSession.createDisplaySession(TEST_TOKEN);
+ private ContentRecordingSession mTaskSession;
private static Point sSurfaceSize;
private ContentRecorder mContentRecorder;
private SurfaceControl mRecordedSurface;
+ // Handle feature flag.
+ private ConfigListener mConfigListener;
+ private CountDownLatch mLatch;
@Before public void setUp() {
- // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
- // mirror.
- setUpDefaultTaskDisplayAreaWindowToken();
-
// GIVEN SurfaceControl can successfully mirror the provided surface.
sSurfaceSize = new Point(
mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
@@ -84,12 +90,32 @@
sSurfaceSize.x, sSurfaceSize.y,
DisplayMetrics.DENSITY_140, new Surface(), VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
final int displayId = virtualDisplay.getDisplay().getDisplayId();
- mDefaultSession.setDisplayId(displayId);
-
mWm.mRoot.onDisplayAdded(displayId);
- final DisplayContent mVirtualDisplayContent = mWm.mRoot.getDisplayContent(displayId);
- mContentRecorder = new ContentRecorder(mVirtualDisplayContent);
- spyOn(mVirtualDisplayContent);
+ final DisplayContent virtualDisplayContent = mWm.mRoot.getDisplayContent(displayId);
+ mContentRecorder = new ContentRecorder(virtualDisplayContent);
+ spyOn(virtualDisplayContent);
+
+ // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+ // record.
+ setUpDefaultTaskDisplayAreaWindowToken();
+ mDisplaySession.setDisplayId(displayId);
+
+ // GIVEN there is a window token associated with a task to record.
+ sTaskWindowContainerToken = setUpTaskWindowContainerToken(virtualDisplayContent);
+ mTaskSession = ContentRecordingSession.createTaskSession(sTaskWindowContainerToken);
+ mTaskSession.setDisplayId(displayId);
+
+ mConfigListener = new ConfigListener();
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ mContext.getMainExecutor(), mConfigListener);
+ mLatch = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_RECORD_TASK_FEATURE,
+ "true", true);
+ }
+
+ @After
+ public void teardown() {
+ DeviceConfig.removeOnPropertiesChangedListener(mConfigListener);
}
@Test
@@ -102,22 +128,74 @@
@Test
public void testUpdateRecording_display() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
}
@Test
- public void testUpdateRecording_task() {
- mDefaultSession.setContentToRecord(RECORD_CONTENT_TASK);
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ public void testUpdateRecording_display_nullToken() {
+ ContentRecordingSession session = ContentRecordingSession.createDisplaySession(TEST_TOKEN);
+ session.setDisplayId(mDisplaySession.getDisplayId());
+ session.setTokenToRecord(null);
+ mContentRecorder.setContentRecordingSession(session);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
}
@Test
+ public void testUpdateRecording_display_noWindowContainer() {
+ doReturn(null).when(
+ mWm.mWindowContextListenerController).getContainer(any());
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ }
+
+ @Test
+ public void testUpdateRecording_task_featureDisabled() {
+ mLatch = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_RECORD_TASK_FEATURE,
+ "false", false);
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ }
+
+ @Test
+ public void testUpdateRecording_task_featureEnabled() {
+ // Feature already enabled; don't need to again.
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+ }
+
+ @Test
+ public void testUpdateRecording_task_nullToken() {
+ ContentRecordingSession session = ContentRecordingSession.createTaskSession(
+ sTaskWindowContainerToken);
+ session.setDisplayId(mDisplaySession.getDisplayId());
+ session.setTokenToRecord(null);
+ mContentRecorder.setContentRecordingSession(session);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ // TODO(b/219761722) validate VirtualDisplay is torn down when can't set up task recording.
+ }
+
+ @Test
+ public void testUpdateRecording_task_noWindowContainer() {
+ // Use the window container token of the DisplayContent, rather than task.
+ ContentRecordingSession invalidTaskSession = ContentRecordingSession.createTaskSession(
+ new WindowContainer.RemoteToken(mDisplayContent));
+ mContentRecorder.setContentRecordingSession(invalidTaskSession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ // TODO(b/219761722) validate VirtualDisplay is torn down when can't set up task recording.
+ }
+
+ @Test
public void testUpdateRecording_wasPaused() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
mContentRecorder.pauseRecording();
@@ -126,16 +204,6 @@
}
@Test
- public void testUpdateRecording_wasStopped() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
- mContentRecorder.updateRecording();
-
- mContentRecorder.remove();
- mContentRecorder.updateRecording();
- assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
- }
-
- @Test
public void testOnConfigurationChanged_neverRecording() {
mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
@@ -146,7 +214,7 @@
@Test
public void testOnConfigurationChanged_resizesSurface() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
@@ -158,7 +226,7 @@
@Test
public void testPauseRecording_pausesRecording() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
mContentRecorder.pauseRecording();
@@ -173,7 +241,7 @@
@Test
public void testRemove_stopsRecording() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
mContentRecorder.remove();
@@ -188,8 +256,9 @@
@Test
public void testUpdateMirroredSurface_capturedAreaResized() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
// WHEN attempting to mirror on the virtual display, and the captured content is resized.
float xScale = 0.7f;
@@ -197,13 +266,14 @@
Rect displayAreaBounds = new Rect(0, 0, Math.round(sSurfaceSize.x * xScale),
Math.round(sSurfaceSize.y * yScale));
mContentRecorder.updateMirroredSurface(mTransaction, displayAreaBounds, sSurfaceSize);
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
// THEN content in the captured DisplayArea is scaled to fit the surface size.
verify(mTransaction, atLeastOnce()).setMatrix(mRecordedSurface, 1.0f / yScale, 0, 0,
1.0f / yScale);
// THEN captured content is positioned in the centre of the output surface.
- float scaledWidth = displayAreaBounds.width() / xScale;
- float xInset = (sSurfaceSize.x - scaledWidth) / 2;
+ int scaledWidth = Math.round((float) displayAreaBounds.width() / xScale);
+ int xInset = (sSurfaceSize.x - scaledWidth) / 2;
verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, xInset, 0);
}
@@ -222,6 +292,18 @@
}
/**
+ * Creates a {@link android.window.WindowContainerToken} associated with a task, in order for
+ * that task to be recorded.
+ */
+ private IBinder setUpTaskWindowContainerToken(DisplayContent displayContent) {
+ final Task rootTask = createTask(displayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+ // Ensure the task is not empty.
+ createActivityRecord(displayContent, task);
+ return task.getTaskInfo().token.asBinder();
+ }
+
+ /**
* SurfaceControl successfully creates a mirrored surface of the given size.
*/
private SurfaceControl surfaceControlMirrors(Point surfaceSize) {
@@ -236,4 +318,13 @@
anyInt());
return mirroredSurface;
}
+
+ private class ConfigListener implements DeviceConfig.OnPropertiesChangedListener {
+ @Override
+ public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
+ if (mLatch != null && properties.getKeyset().contains(KEY_RECORD_TASK_FEATURE)) {
+ mLatch.countDown();
+ }
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 25d7334..b4d305b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -932,7 +932,7 @@
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
assertNotNull(o.mChangedInfo);
assertNotNull(o.mChangedInfo.pictureInPictureParams);
- final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatioRational();
+ final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatio();
assertEquals(3, ratio.getNumerator());
assertEquals(4, ratio.getDenominator());
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 837cf8b..cff90bb 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -504,7 +504,12 @@
/** Control whether users can choose a network operator. */
public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
- /** Used in Cellular Network Settings for preferred network type. */
+ /**
+ * Used in the Preferred Network Types menu to determine if the 2G option is displayed.
+ * Value defaults to false as of Android T to discourage the use of insecure 2G protocols.
+ *
+ * @see #KEY_HIDE_ENABLE_2G
+ */
public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
/**
@@ -8594,7 +8599,7 @@
sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false);
sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false);
sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
- sDefaults.putBoolean(KEY_PREFER_2G_BOOL, true);
+ sDefaults.putBoolean(KEY_PREFER_2G_BOOL, false);
sDefaults.putBoolean(KEY_4G_ONLY_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_APN_SETTING_CDMA_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_CDMA_CHOICES_BOOL, false);
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index d2a4c3e..3a3b363 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -1090,13 +1090,6 @@
*/
public static final int NO_RETRY_FAILURE = 0x1000B;
- /**
- * Traffic descriptors in DataCallResponse is empty.
- *
- * @hide
- */
- public static final int NO_TRAFFIC_DESCRIPTORS = 0x1000C;
-
private static final Map<Integer, String> sFailCauseMap;
static {
sFailCauseMap = new HashMap<>();
@@ -1531,7 +1524,6 @@
sFailCauseMap.put(SERVICE_TEMPORARILY_UNAVAILABLE, "SERVICE_TEMPORARILY_UNAVAILABLE");
sFailCauseMap.put(REQUEST_NOT_SUPPORTED, "REQUEST_NOT_SUPPORTED");
sFailCauseMap.put(NO_RETRY_FAILURE, "NO_RETRY_FAILURE");
- sFailCauseMap.put(NO_TRAFFIC_DESCRIPTORS, "NO_TRAFFIC_DESCRIPTORS");
}
private DataFailCause() {
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 532679c..8143da5 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -549,7 +549,6 @@
* Returns the profile id to which the APN saved in modem.
*
* @return the profile id of the APN
- * @hide
*/
public int getProfileId() {
return mProfileId;
@@ -558,8 +557,7 @@
/**
* Returns if the APN setting is persistent on the modem.
*
- * @return is the APN setting to be set in modem
- * @hide
+ * @return {@code true} if the APN setting is persistent on the modem.
*/
public boolean isPersistent() {
return mPersistent;
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 892eb29..bd346d5 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -31,6 +31,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.telephony.AccessNetworkConstants.RadioAccessNetworkType;
import android.util.Log;
import android.util.SparseArray;
@@ -166,7 +167,8 @@
* link properties of the existing data connection, otherwise null.
* @param callback The result callback for this request.
*/
- public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile,
+ public void setupDataCall(
+ @RadioAccessNetworkType int accessNetworkType, @NonNull DataProfile dataProfile,
boolean isRoaming, boolean allowRoaming,
@SetupDataReason int reason, @Nullable LinkProperties linkProperties,
@NonNull DataServiceCallback callback) {
@@ -214,7 +216,8 @@
* for example, a zero-rating slice.
* @param callback The result callback for this request.
*/
- public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile,
+ public void setupDataCall(
+ @RadioAccessNetworkType int accessNetworkType, @NonNull DataProfile dataProfile,
boolean isRoaming, boolean allowRoaming,
@SetupDataReason int reason,
@Nullable LinkProperties linkProperties,
@@ -294,6 +297,9 @@
* with reason {@link DataService.REQUEST_REASON_HANDOVER}. The target transport now owns
* the transferred resources and is responsible for releasing them.
*
+ * <p/>
+ * Note that the callback will be executed on binder thread.
+ *
* @param cid The identifier of the data call which is provided in {@link DataCallResponse}
* @param callback The result callback for this request.
*
@@ -322,6 +328,9 @@
* </li>
* </ul>
*
+ * <p/>
+ * Note that the callback will be executed on binder thread.
+ *
* @param cid The identifier of the data call which is provided in {@link DataCallResponse}
* @param callback The result callback for this request.
*
diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
index fe44530..5ffee56 100644
--- a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
@@ -32,7 +32,12 @@
import java.util.Objects;
/**
- * Provides Qos attributes of an EPS bearer.
+ * Provides QOS attributes of an EPS bearer.
+ *
+ * <p> The dedicated EPS bearer along with QOS is allocated by the LTE network and notified to the
+ * device. The Telephony framework creates the {@link EpsBearerQosSessionAttributes} object which
+ * represents the QOS of the dedicated bearer and notifies the same to applications via
+ * {@link QosCallback}.
*
* {@hide}
*/
diff --git a/tools/traceinjection/Android.bp b/tools/traceinjection/Android.bp
new file mode 100644
index 0000000..1395c5f
--- /dev/null
+++ b/tools/traceinjection/Android.bp
@@ -0,0 +1,49 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_binary_host {
+ name: "traceinjection",
+ manifest: "manifest.txt",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "asm-7.0",
+ "asm-commons-7.0",
+ "asm-tree-7.0",
+ "asm-analysis-7.0",
+ "guava-21.0",
+ ],
+}
+
+java_library_host {
+ name: "TraceInjectionTests-Uninjected",
+ srcs: ["test/**/*.java"],
+ static_libs: [
+ "junit",
+ ],
+}
+
+java_genrule_host {
+ name: "TraceInjectionTests-Injected",
+ srcs: [":TraceInjectionTests-Uninjected"],
+ tools: ["traceinjection"],
+ cmd: "$(location traceinjection) " +
+ " --annotation \"com/android/traceinjection/Trace\"" +
+ " --start \"com/android/traceinjection/InjectionTests.traceStart\"" +
+ " --end \"com/android/traceinjection/InjectionTests.traceEnd\"" +
+ " -o $(out) " +
+ " -i $(in)",
+ out: ["TraceInjectionTests-Injected.jar"],
+}
+
+java_test_host {
+ name: "TraceInjectionTests",
+ static_libs: [
+ "TraceInjectionTests-Injected",
+ ],
+}
diff --git a/tools/traceinjection/manifest.txt b/tools/traceinjection/manifest.txt
new file mode 100644
index 0000000..7f4ee1d
--- /dev/null
+++ b/tools/traceinjection/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.android.traceinjection.Main
diff --git a/tools/traceinjection/src/com/android/traceinjection/Main.java b/tools/traceinjection/src/com/android/traceinjection/Main.java
new file mode 100644
index 0000000..190df81
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/Main.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.traceinjection;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
+import java.io.BufferedInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+public class Main {
+ public static void main(String[] args) throws IOException {
+ String inJar = null;
+ String outJar = null;
+ String annotation = null;
+ String traceStart = null;
+ String traceEnd = null;
+
+ // All arguments require a value currently, so just make sure we have an even number and
+ // then process them all two at a time.
+ if (args.length % 2 != 0) {
+ throw new IllegalArgumentException("Argument is missing corresponding value");
+ }
+ for (int i = 0; i < args.length - 1; i += 2) {
+ final String arg = args[i].trim();
+ final String argValue = args[i + 1].trim();
+ if ("-i".equals(arg)) {
+ inJar = argValue;
+ } else if ("-o".equals(arg)) {
+ outJar = argValue;
+ } else if ("--annotation".equals(arg)) {
+ annotation = argValue;
+ } else if ("--start".equals(arg)) {
+ traceStart = argValue;
+ } else if ("--end".equals(arg)) {
+ traceEnd = argValue;
+ } else {
+ throw new IllegalArgumentException("Unknown argument: " + arg);
+ }
+ }
+
+ if (inJar == null) {
+ throw new IllegalArgumentException("input jar is required");
+ }
+
+ if (outJar == null) {
+ throw new IllegalArgumentException("output jar is required");
+ }
+
+ if (annotation == null) {
+ throw new IllegalArgumentException("trace annotation is required");
+ }
+
+ if (traceStart == null) {
+ throw new IllegalArgumentException("start trace method is required");
+ }
+
+ if (traceEnd == null) {
+ throw new IllegalArgumentException("end trace method is required");
+ }
+
+ TraceInjectionConfiguration params =
+ new TraceInjectionConfiguration(annotation, traceStart, traceEnd);
+
+ try (
+ ZipFile zipSrc = new ZipFile(inJar);
+ ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(outJar));
+ ) {
+ Enumeration<? extends ZipEntry> srcEntries = zipSrc.entries();
+ while (srcEntries.hasMoreElements()) {
+ ZipEntry entry = srcEntries.nextElement();
+ ZipEntry newEntry = new ZipEntry(entry.getName());
+ newEntry.setTime(entry.getTime());
+ zos.putNextEntry(newEntry);
+ BufferedInputStream bis = new BufferedInputStream(zipSrc.getInputStream(entry));
+
+ if (entry.getName().endsWith(".class")) {
+ convert(bis, zos, params);
+ } else {
+ while (bis.available() > 0) {
+ zos.write(bis.read());
+ }
+ zos.closeEntry();
+ bis.close();
+ }
+ }
+ zos.finish();
+ }
+ }
+
+ private static void convert(InputStream in, OutputStream out,
+ TraceInjectionConfiguration params) throws IOException {
+ ClassReader cr = new ClassReader(in);
+ ClassWriter cw = new ClassWriter(0);
+ TraceInjectionClassVisitor cv = new TraceInjectionClassVisitor(cw, params);
+ cr.accept(cv, ClassReader.EXPAND_FRAMES);
+ byte[] data = cw.toByteArray();
+ out.write(data);
+ }
+}
diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java
new file mode 100644
index 0000000..863f976
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.traceinjection;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * {@link ClassVisitor} that injects tracing code to methods annotated with the configured
+ * annotation.
+ */
+public class TraceInjectionClassVisitor extends ClassVisitor {
+ private final TraceInjectionConfiguration mParams;
+ public TraceInjectionClassVisitor(ClassVisitor classVisitor,
+ TraceInjectionConfiguration params) {
+ super(Opcodes.ASM7, classVisitor);
+ mParams = params;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions) {
+ MethodVisitor chain = super.visitMethod(access, name, desc, signature, exceptions);
+ return new TraceInjectionMethodAdapter(chain, access, name, desc, mParams);
+ }
+}
diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionConfiguration.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionConfiguration.java
new file mode 100644
index 0000000..f9595bd
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionConfiguration.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.traceinjection;
+
+/**
+ * Configuration data for trace method injection.
+ */
+public class TraceInjectionConfiguration {
+ public final String annotation;
+ public final String startMethodClass;
+ public final String startMethodName;
+ public final String endMethodClass;
+ public final String endMethodName;
+
+ public TraceInjectionConfiguration(String annotation, String startMethod, String endMethod) {
+ this.annotation = annotation;
+ String[] startMethodComponents = parseMethod(startMethod);
+ String[] endMethodComponents = parseMethod(endMethod);
+ startMethodClass = startMethodComponents[0];
+ startMethodName = startMethodComponents[1];
+ endMethodClass = endMethodComponents[0];
+ endMethodName = endMethodComponents[1];
+ }
+
+ public String toString() {
+ return "TraceInjectionParams{annotation=" + annotation
+ + ", startMethod=" + startMethodClass + "." + startMethodName
+ + ", endMethod=" + endMethodClass + "." + endMethodName + "}";
+ }
+
+ private static String[] parseMethod(String method) {
+ String[] methodComponents = method.split("\\.");
+ if (methodComponents.length != 2) {
+ throw new IllegalArgumentException("Invalid method descriptor: " + method);
+ }
+ return methodComponents;
+ }
+}
diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java
new file mode 100644
index 0000000..c2bbddc
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.traceinjection;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.AdviceAdapter;
+import org.objectweb.asm.commons.Method;
+
+/**
+ * Adapter that injects tracing code to methods annotated with the configured annotation.
+ *
+ * Assuming the configured annotation is {@code @Trace} and the configured methods are
+ * {@code Tracing.begin()} and {@code Tracing.end()}, it effectively transforms:
+ *
+ * <pre>{@code
+ * @Trace
+ * void method() {
+ * doStuff();
+ * }
+ * }</pre>
+ *
+ * into:
+ * <pre>{@code
+ * @Trace
+ * void method() {
+ * Tracing.begin();
+ * try {
+ * doStuff();
+ * } finally {
+ * Tracing.end();
+ * }
+ * }
+ * }</pre>
+ */
+public class TraceInjectionMethodAdapter extends AdviceAdapter {
+ private final TraceInjectionConfiguration mParams;
+ private final Label mStartFinally = newLabel();
+ private final boolean mIsConstructor;
+
+ private boolean mShouldTrace;
+ private long mTraceId;
+ private String mTraceLabel;
+
+ public TraceInjectionMethodAdapter(MethodVisitor methodVisitor, int access,
+ String name, String descriptor, TraceInjectionConfiguration params) {
+ super(Opcodes.ASM7, methodVisitor, access, name, descriptor);
+ mParams = params;
+ mIsConstructor = "<init>".equals(name);
+ }
+
+ @Override
+ public void visitCode() {
+ super.visitCode();
+ if (mShouldTrace) {
+ visitLabel(mStartFinally);
+ }
+ }
+
+ @Override
+ protected void onMethodEnter() {
+ if (!mShouldTrace) {
+ return;
+ }
+ Type type = Type.getType(toJavaSpecifier(mParams.startMethodClass));
+ Method trace = Method.getMethod("void " + mParams.startMethodName + " (long, String)");
+ push(mTraceId);
+ push(getTraceLabel());
+ invokeStatic(type, trace);
+ }
+
+ private String getTraceLabel() {
+ return !isEmpty(mTraceLabel) ? mTraceLabel : getName();
+ }
+
+ @Override
+ protected void onMethodExit(int opCode) {
+ // Any ATHROW exits will be caught as part of our exception-handling block, so putting it
+ // here would cause us to call the end trace method multiple times.
+ if (opCode != ATHROW) {
+ onFinally();
+ }
+ }
+
+ private void onFinally() {
+ if (!mShouldTrace) {
+ return;
+ }
+ Type type = Type.getType(toJavaSpecifier(mParams.endMethodClass));
+ Method trace = Method.getMethod("void " + mParams.endMethodName + " (long)");
+ push(mTraceId);
+ invokeStatic(type, trace);
+ }
+
+ @Override
+ public void visitMaxs(int maxStack, int maxLocals) {
+ final int minStackSize;
+ if (mShouldTrace) {
+ Label endFinally = newLabel();
+ visitLabel(endFinally);
+ catchException(mStartFinally, endFinally, null);
+ // The stack will always contain exactly one element: the exception we caught
+ final Object[] stack = new Object[]{ "java/lang/Throwable"};
+ // Because we use EXPAND_FRAMES, the frame type must always be F_NEW.
+ visitFrame(F_NEW, /* numLocal= */ 0, /* local= */ null, stack.length, stack);
+ onFinally();
+ // Rethrow the exception that we caught in the finally block.
+ throwException();
+
+ // Make sure we have at least enough stack space to push the trace arguments
+ // (long, String)
+ minStackSize = Type.LONG_TYPE.getSize() + Type.getType(String.class).getSize();
+ } else {
+ // We didn't inject anything, so no need for additional stack space.
+ minStackSize = 0;
+ }
+
+ super.visitMaxs(Math.max(minStackSize, maxStack), maxLocals);
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+ AnnotationVisitor av = super.visitAnnotation(descriptor, visible);
+ if (descriptor.equals(toJavaSpecifier(mParams.annotation))) {
+ if (mIsConstructor) {
+ // TODO: Support constructor tracing. At the moment, constructors aren't supported
+ // because you can't put an exception handler around a super() call within the
+ // constructor itself.
+ throw new IllegalStateException("Cannot trace constructors");
+ }
+ av = new TracingAnnotationVisitor(av);
+ }
+ return av;
+ }
+
+ /**
+ * An AnnotationVisitor that pulls the trace ID and label information from the configured
+ * annotation.
+ */
+ class TracingAnnotationVisitor extends AnnotationVisitor {
+
+ TracingAnnotationVisitor(AnnotationVisitor annotationVisitor) {
+ super(Opcodes.ASM7, annotationVisitor);
+ }
+
+ @Override
+ public void visit(String name, Object value) {
+ if ("tag".equals(name)) {
+ mTraceId = (long) value;
+ // If we have a trace annotation and ID, then we have everything we need to trace
+ mShouldTrace = true;
+ } else if ("label".equals(name)) {
+ mTraceLabel = (String) value;
+ }
+ super.visit(name, value);
+ }
+ }
+
+ private static String toJavaSpecifier(String klass) {
+ return "L" + klass + ";";
+ }
+
+ private static boolean isEmpty(String str) {
+ return str == null || "".equals(str);
+ }
+}
diff --git a/tools/traceinjection/test/com/android/traceinjection/InjectionTests.java b/tools/traceinjection/test/com/android/traceinjection/InjectionTests.java
new file mode 100644
index 0000000..81bf235
--- /dev/null
+++ b/tools/traceinjection/test/com/android/traceinjection/InjectionTests.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.traceinjection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(JUnit4.class)
+public class InjectionTests {
+ public static final int TRACE_TAG = 42;
+ public static final String CUSTOM_TRACE_NAME = "Custom";
+
+ public static final TraceTracker TRACKER = new TraceTracker();
+
+ @After
+ public void tearDown() {
+ TRACKER.reset();
+ }
+
+ @Test
+ public void testDefaultLabel() {
+ assertTraces(this::tracedMethod, "tracedMethod");
+ tracedMethodThrowsAndCatches();
+ }
+
+ @Test
+ public void testCustomLabel() {
+ assertTraces(this::tracedMethodHasCustomName, CUSTOM_TRACE_NAME);
+ }
+
+ @Test
+ public void testTracedMethodsStillThrow() {
+ assertTraces(() -> assertThrows(IllegalArgumentException.class, this::tracedMethodThrows),
+ "tracedMethodThrows");
+ // Also test that we rethrow exceptions from method calls. This is slightly different from
+ // the previous case because the ATHROW instruction is not actually present at all in the
+ // bytecode of the instrumented method.
+ TRACKER.reset();
+ assertTraces(() -> assertThrows(NullPointerException.class,
+ this::tracedMethodCallsThrowingMethod),
+ "tracedMethodCallsThrowingMethod");
+ }
+
+ @Test
+ public void testNestedTracedMethods() {
+ assertTraces(this::outerTracedMethod, "outerTracedMethod", "innerTracedMethod");
+ }
+
+ @Test
+ public void testTracedMethodWithCatchBlock() {
+ assertTraces(this::tracedMethodThrowsAndCatches, "tracedMethodThrowsAndCatches");
+ }
+
+ @Test
+ public void testTracedMethodWithFinallyBlock() {
+ assertTraces(() -> assertThrows(IllegalArgumentException.class,
+ this::tracedMethodThrowWithFinally), "tracedMethodThrowWithFinally");
+ }
+
+ @Test
+ public void testNonVoidMethod() {
+ assertTraces(this::tracedNonVoidMethod, "tracedNonVoidMethod");
+ }
+
+ @Test
+ public void testNonVoidMethodReturnsWithinCatches() {
+ assertTraces(this::tracedNonVoidMethodReturnsWithinCatches,
+ "tracedNonVoidMethodReturnsWithinCatches");
+ }
+
+ @Test
+ public void testNonVoidMethodReturnsWithinFinally() {
+ assertTraces(this::tracedNonVoidMethodReturnsWithinFinally,
+ "tracedNonVoidMethodReturnsWithinFinally");
+ }
+
+ @Test
+ public void testTracedStaticMethod() {
+ assertTraces(InjectionTests::tracedStaticMethod, "tracedStaticMethod");
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethod() {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethodThrows() {
+ throw new IllegalArgumentException();
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethodCallsThrowingMethod() {
+ throwingMethod();
+ }
+
+ private void throwingMethod() {
+ throw new NullPointerException();
+ }
+
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethodThrowsAndCatches() {
+ try {
+ throw new IllegalArgumentException();
+ } catch (IllegalArgumentException ignored) {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethodThrowWithFinally() {
+ try {
+ throw new IllegalArgumentException();
+ } finally {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+ }
+
+ @Trace(tag = TRACE_TAG, label = CUSTOM_TRACE_NAME)
+ public void tracedMethodHasCustomName() {
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void outerTracedMethod() {
+ innerTracedMethod();
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void innerTracedMethod() {
+ assertEquals(2, TRACKER.getTraceCount(TRACE_TAG));
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public int tracedNonVoidMethod() {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ return 0;
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public int tracedNonVoidMethodReturnsWithinCatches() {
+ try {
+ throw new IllegalArgumentException();
+ } catch (IllegalArgumentException ignored) {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ return 0;
+ }
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public int tracedNonVoidMethodReturnsWithinFinally() {
+ try {
+ throw new IllegalArgumentException();
+ } finally {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ return 0;
+ }
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public static void tracedStaticMethod() {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+
+ public void assertTraces(Runnable r, String... traceLabels) {
+ r.run();
+ assertEquals(Arrays.asList(traceLabels), TRACKER.getTraceLabels(TRACE_TAG));
+ TRACKER.assertAllTracesClosed();
+ }
+
+ public static void traceStart(long tag, String name) {
+ TRACKER.onTraceStart(tag, name);
+ }
+
+ public static void traceEnd(long tag) {
+ TRACKER.onTraceEnd(tag);
+ }
+
+ static class TraceTracker {
+ private final Map<Long, List<String>> mTraceLabelsByTag = new HashMap<>();
+ private final Map<Long, Integer> mTraceCountsByTag = new HashMap<>();
+
+ public void onTraceStart(long tag, String name) {
+ getTraceLabels(tag).add(name);
+ mTraceCountsByTag.put(tag, mTraceCountsByTag.getOrDefault(tag, 0) + 1);
+ }
+
+ public void onTraceEnd(long tag) {
+ final int newCount = getTraceCount(tag) - 1;
+ if (newCount < 0) {
+ throw new IllegalStateException("Trace count has gone negative for tag " + tag);
+ }
+ mTraceCountsByTag.put(tag, newCount);
+ }
+
+ public void reset() {
+ mTraceLabelsByTag.clear();
+ mTraceCountsByTag.clear();
+ }
+
+ public List<String> getTraceLabels(long tag) {
+ if (!mTraceLabelsByTag.containsKey(tag)) {
+ mTraceLabelsByTag.put(tag, new ArrayList<>());
+ }
+ return mTraceLabelsByTag.get(tag);
+ }
+
+ public int getTraceCount(long tag) {
+ return mTraceCountsByTag.getOrDefault(tag, 0);
+ }
+
+ public void assertAllTracesClosed() {
+ for (Map.Entry<Long, Integer> count: mTraceCountsByTag.entrySet()) {
+ final String errorMsg = "Tag " + count.getKey() + " is not fully closed (count="
+ + count.getValue() + ")";
+ assertEquals(errorMsg, 0, (int) count.getValue());
+ }
+ }
+ }
+}
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl b/tools/traceinjection/test/com/android/traceinjection/Trace.java
similarity index 76%
copy from media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl
copy to tools/traceinjection/test/com/android/traceinjection/Trace.java
index 5e15016..9e1c545 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl
+++ b/tools/traceinjection/test/com/android/traceinjection/Trace.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,9 @@
* limitations under the License.
*/
-package android.media.tv.interactive;
+package com.android.traceinjection;
-parcelable TvInteractiveAppInfo;
\ No newline at end of file
+public @interface Trace {
+ long tag();
+ String label() default "";
+}