diff options
195 files changed, 3455 insertions, 2348 deletions
diff --git a/ApiDocs.bp b/ApiDocs.bp index 038ee6501ded..5ec107da8b94 100644 --- a/ApiDocs.bp +++ b/ApiDocs.bp @@ -231,7 +231,7 @@ droiddoc { "android.whichdoc offline", ], compat_config: ":global-compat-config", - proofread_file: "offline-sdk-docs-proofrerad.txt", + proofread_file: "offline-sdk-docs-proofread.txt", args: framework_docs_only_args + " -offlinemode -title \"Android SDK\"", static_doc_index_redirect: "docs/docs-preview-index.html", } @@ -248,7 +248,7 @@ droiddoc { hdf: [ "android.whichdoc offline", ], - proofread_file: "offline-sdk-referenceonly-docs-proofrerad.txt", + proofread_file: "offline-sdk-referenceonly-docs-proofread.txt", args: framework_docs_only_args + " -offlinemode -title \"Android SDK\" -referenceonly", static_doc_index_redirect: "docs/docs-documentation-redirect.html", static_doc_properties: "docs/source.properties", @@ -266,7 +266,7 @@ droiddoc { hdf: [ "android.whichdoc offline", ], - proofread_file: "offline-system-sdk-referenceonly-docs-proofrerad.txt", + proofread_file: "offline-system-sdk-referenceonly-docs-proofread.txt", args: framework_docs_only_args + " -hide 101 -hide 104 -hide 108" + " -offlinemode -title \"Android System SDK\" -referenceonly", static_doc_index_redirect: "docs/docs-documentation-redirect.html", @@ -283,7 +283,7 @@ droiddoc { "android.whichdoc online", "android.hasSamples true", ], - proofread_file: "online-sdk-docs-proofrerad.txt", + proofread_file: "online-sdk-docs-proofread.txt", args: framework_docs_only_args + " -toroot / -samplegroup Admin " + " -samplegroup Background " + @@ -312,7 +312,7 @@ droiddoc { "android.whichdoc online", "android.hasSamples true", ], - proofread_file: "online-system-api-sdk-docs-proofrerad.txt", + proofread_file: "online-system-api-sdk-docs-proofread.txt", args: framework_docs_only_args + " -referenceonly " + " -title \"Android SDK - Including system APIs.\" " + @@ -347,7 +347,7 @@ droiddoc { "android.whichdoc online", "android.hasSamples true", ], - proofread_file: "ds-docs-proofrerad.txt", + proofread_file: "ds-docs-proofread.txt", args: framework_docs_only_args + " -toroot / -yamlV2 -metalavaApiSince -samplegroup Admin " + " -samplegroup Background " + @@ -458,7 +458,7 @@ droiddoc { "android.whichdoc online", "android.hasSamples true", ], - proofread_file: "online-sdk-dev-docs-proofrerad.txt", + proofread_file: "online-sdk-dev-docs-proofread.txt", args: framework_docs_only_args + " -toroot / -samplegroup Admin " + " -samplegroup Background " + @@ -483,7 +483,7 @@ droiddoc { srcs: [ ":framework-doc-stubs", ], - proofread_file: "hidden-docs-proofrerad.txt", + proofread_file: "hidden-docs-proofread.txt", args: framework_docs_only_args + " -referenceonly " + " -title \"Android SDK - Including hidden APIs.\"", @@ -31,5 +31,6 @@ per-file */res*/values*/*.xml = byi@google.com, delphij@google.com per-file *.bp = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION} per-file Android.mk = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION} +per-file framework-jarjar-rules.txt = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION} per-file TestProtoLibraries.bp = file:platform/platform_testing:/libraries/health/OWNERS per-file TestProtoLibraries.bp = file:platform/tools/tradefederation:/OWNERS diff --git a/TRACE_OWNERS b/TRACE_OWNERS new file mode 100644 index 000000000000..f746a162bc8f --- /dev/null +++ b/TRACE_OWNERS @@ -0,0 +1,5 @@ +# OWNERS of Trace-related files +primiano@google.com +timmurray@google.com +jjaggi@google.com +jreck@google.com diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java index da429af7e351..61424ae0e158 100644 --- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java +++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java @@ -270,6 +270,16 @@ public class AlarmManager { @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S) public static final long ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS = 185199076L; + /** + * For apps targeting {@link Build.VERSION_CODES#TIRAMISU} or above, certain kinds of apps can + * use {@link Manifest.permission#USE_EXACT_ALARM} to schedule exact alarms. + * + * @hide + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + public static final long ENABLE_USE_EXACT_ALARM = 218533173L; + @UnsupportedAppUsage private final IAlarmManager mService; private final Context mContext; diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java index a09f39f26eab..f67e8d2baa11 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -1827,30 +1827,9 @@ public class AlarmManagerService extends SystemService { newAppIds.add(UserHandle.getAppId(uid)); } } - final ArraySet<Integer> removed = new ArraySet<>(mExactAlarmCandidates); - removed.removeAll(newAppIds); - // This code is only called on package_added and boot. The set {removed} is only expected to - // be non-empty when a package was updated and it removed the permission from its manifest. - for (int i = 0; i < removed.size(); i++) { - final int removedAppId = removed.valueAt(i); - synchronized (mLock) { - Slog.i(TAG, "App id " + removedAppId + " lost SCHEDULE_EXACT_ALARM on update"); + // Some packages may have lost permission to schedule exact alarms on update, their alarms + // will be removed while handling CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE after this. - final Predicate<Alarm> whichAlarms = a -> { - if (UserHandle.getAppId(a.uid) != removedAppId || a.windowLength != 0) { - return false; - } - if (!isExactAlarmChangeEnabled(a.packageName, UserHandle.getUserId(a.uid))) { - return false; - } - if (hasUseExactAlarmPermission(a.packageName, a.uid)) { - return false; - } - return !isExemptFromExactAlarmPermission(a.uid); - }; - removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_EXACT_PERMISSION_REVOKED); - } - } // No need to lock. Assignment is always atomic. mExactAlarmCandidates = Collections.unmodifiableSet(newAppIds); } @@ -1910,7 +1889,7 @@ public class AlarmManagerService extends SystemService { || !isExactAlarmChangeEnabled(packageName, userId)) { return; } - if (hasUseExactAlarmPermission(packageName, uid)) { + if (hasUseExactAlarmInternal(packageName, uid)) { return; } @@ -2533,8 +2512,9 @@ public class AlarmManagerService extends SystemService { } @Override - public boolean hasScheduleExactAlarm(String packageName, int uid) { - return hasScheduleExactAlarmInternal(packageName, uid); + public boolean hasExactAlarmPermission(String packageName, int uid) { + return hasScheduleExactAlarmInternal(packageName, uid) + || hasUseExactAlarmInternal(packageName, uid); } @Override @@ -2558,21 +2538,19 @@ public class AlarmManagerService extends SystemService { return appOpMode == AppOpsManager.MODE_ALLOWED; } - boolean hasUseExactAlarmPermission(String packageName, int uid) { - return PermissionChecker.checkPermissionForPreflight(getContext(), + boolean hasUseExactAlarmInternal(String packageName, int uid) { + return isUseExactAlarmEnabled(packageName, UserHandle.getUserId(uid)) + && (PermissionChecker.checkPermissionForPreflight(getContext(), Manifest.permission.USE_EXACT_ALARM, PermissionChecker.PID_UNKNOWN, uid, - packageName) == PermissionChecker.PERMISSION_GRANTED; + packageName) == PermissionChecker.PERMISSION_GRANTED); } boolean hasScheduleExactAlarmInternal(String packageName, int uid) { - if (hasUseExactAlarmPermission(packageName, uid)) { - return true; - } + final long start = mStatLogger.getTime(); + // Not using getScheduleExactAlarmState as this can avoid some calls to AppOpsService. // Not using #mLastOpScheduleExactAlarm as it may contain stale values. // No locking needed as all internal containers being queried are immutable. - - final long start = mStatLogger.getTime(); final boolean hasPermission; if (!mExactAlarmCandidates.contains(UserHandle.getAppId(uid))) { hasPermission = false; @@ -2703,7 +2681,8 @@ public class AlarmManagerService extends SystemService { lowerQuota = allowWhileIdle; idleOptions = allowWhileIdle ? mOptsWithFgs.toBundle() : null; } - if (needsPermission && !hasScheduleExactAlarmInternal(callingPackage, callingUid)) { + if (needsPermission && !hasScheduleExactAlarmInternal(callingPackage, callingUid) + && !hasUseExactAlarmInternal(callingPackage, callingUid)) { if (!isExemptFromExactAlarmPermission(callingUid)) { final String errorMessage = "Caller " + callingPackage + " needs to hold " + Manifest.permission.SCHEDULE_EXACT_ALARM + " to set " @@ -2768,7 +2747,8 @@ public class AlarmManagerService extends SystemService { return true; } return isExemptFromExactAlarmPermission(packageUid) - || hasScheduleExactAlarmInternal(packageName, packageUid); + || hasScheduleExactAlarmInternal(packageName, packageUid) + || hasUseExactAlarmInternal(packageName, packageUid); } @Override @@ -2875,6 +2855,11 @@ public class AlarmManagerService extends SystemService { packageName, UserHandle.of(userId)); } + private static boolean isUseExactAlarmEnabled(String packageName, int userId) { + return CompatChanges.isChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, + packageName, UserHandle.of(userId)); + } + @NeverCompile // Avoid size overhead of debugging code. void dumpImpl(IndentingPrintWriter pw) { synchronized (mLock) { @@ -3784,7 +3769,7 @@ public class AlarmManagerService extends SystemService { if (!isExactAlarmChangeEnabled(changedPackage, userId)) { continue; } - if (hasUseExactAlarmPermission(changedPackage, uid)) { + if (hasUseExactAlarmInternal(changedPackage, uid)) { continue; } final int appOpMode; @@ -3817,8 +3802,9 @@ public class AlarmManagerService extends SystemService { } /** - * Called when an app loses {@link Manifest.permission#SCHEDULE_EXACT_ALARM} to remove alarms - * that the app is no longer eligible to use. + * Called when an app loses the permission to use exact alarms. This will happen when the app + * no longer has either {@link Manifest.permission#SCHEDULE_EXACT_ALARM} or + * {@link Manifest.permission#USE_EXACT_ALARM}. * * This is not expected to get called frequently. */ @@ -3828,7 +3814,8 @@ public class AlarmManagerService extends SystemService { || !isExactAlarmChangeEnabled(packageName, UserHandle.getUserId(uid))) { return; } - Slog.w(TAG, "Package " + packageName + ", uid " + uid + " lost SCHEDULE_EXACT_ALARM!"); + Slog.w(TAG, "Package " + packageName + ", uid " + uid + + " lost permission to set exact alarms!"); final Predicate<Alarm> whichAlarms = a -> (a.uid == uid && a.packageName.equals(packageName) && a.windowLength == 0); @@ -4764,7 +4751,8 @@ public class AlarmManagerService extends SystemService { case CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE: packageName = (String) msg.obj; uid = msg.arg1; - if (!hasScheduleExactAlarmInternal(packageName, uid)) { + if (!hasScheduleExactAlarmInternal(packageName, uid) + && !hasUseExactAlarmInternal(packageName, uid)) { synchronized (mLock) { removeExactAlarmsOnPermissionRevokedLocked(uid, packageName, /*killUid = */false); @@ -4936,13 +4924,15 @@ public class AlarmManagerService extends SystemService { mLastOpScheduleExactAlarm.delete(uid); return; case Intent.ACTION_PACKAGE_ADDED: + mHandler.sendEmptyMessage(AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES); if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { + // Some apps may lose permission to set exact alarms on update. + // We need to remove their exact alarms. final String packageUpdated = intent.getData().getSchemeSpecificPart(); mHandler.obtainMessage( AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE, uid, -1, packageUpdated).sendToTarget(); } - mHandler.sendEmptyMessage(AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES); return; case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 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 549badd5ba82..b4238c975d98 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java @@ -16,7 +16,6 @@ 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; @@ -82,6 +81,11 @@ class JobConcurrencyManager { private static final String TAG = JobSchedulerService.TAG + ".Concurrency"; private static final boolean DEBUG = JobSchedulerService.DEBUG; + /** The maximum number of concurrent jobs we'll aim to run at one time. */ + public static final int STANDARD_CONCURRENCY_LIMIT = 16; + /** The maximum number of objects we should retain in memory when not in use. */ + private static final int MAX_RETAINED_OBJECTS = (int) (1.5 * STANDARD_CONCURRENCY_LIMIT); + static final String CONFIG_KEY_PREFIX_CONCURRENCY = "concurrency_"; private static final String KEY_SCREEN_OFF_ADJUSTMENT_DELAY_MS = CONFIG_KEY_PREFIX_CONCURRENCY + "screen_off_adjustment_delay_ms"; @@ -93,7 +97,7 @@ class JobConcurrencyManager { @VisibleForTesting static final String KEY_PKG_CONCURRENCY_LIMIT_REGULAR = CONFIG_KEY_PREFIX_CONCURRENCY + "pkg_concurrency_limit_regular"; - private static final int DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR = MAX_JOB_CONTEXTS_COUNT / 2; + private static final int DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR = STANDARD_CONCURRENCY_LIMIT / 2; /** * Set of possible execution types that a job can have. The actual type(s) of a job are based @@ -309,7 +313,7 @@ class JobConcurrencyManager { private final ArrayList<ContextAssignment> mRecycledStoppable = new ArrayList<>(); private final Pools.Pool<ContextAssignment> mContextAssignmentPool = - new Pools.SimplePool<>(MAX_JOB_CONTEXTS_COUNT); + new Pools.SimplePool<>(MAX_RETAINED_OBJECTS); /** * Set of JobServiceContexts that are actively running jobs. @@ -317,14 +321,16 @@ class JobConcurrencyManager { final List<JobServiceContext> mActiveServices = new ArrayList<>(); /** Set of JobServiceContexts that aren't currently running any jobs. */ - final ArraySet<JobServiceContext> mIdleContexts = new ArraySet<>(); + private final ArraySet<JobServiceContext> mIdleContexts = new ArraySet<>(); + + private int mNumDroppedContexts = 0; private final ArraySet<JobStatus> mRunningJobs = new ArraySet<>(); private final WorkCountTracker mWorkCountTracker = new WorkCountTracker(); private final Pools.Pool<PackageStats> mPkgStatsPool = - new Pools.SimplePool<>(MAX_JOB_CONTEXTS_COUNT); + new Pools.SimplePool<>(MAX_RETAINED_OBJECTS); private final SparseArrayMap<String, PackageStats> mActivePkgStats = new SparseArrayMap<>(); @@ -406,7 +412,7 @@ class JobConcurrencyManager { void onThirdPartyAppsCanStart() { final IBatteryStats batteryStats = IBatteryStats.Stub.asInterface( ServiceManager.getService(BatteryStats.SERVICE_NAME)); - for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) { + for (int i = 0; i < STANDARD_CONCURRENCY_LIMIT; i++) { mIdleContexts.add( new JobServiceContext(mService, this, batteryStats, mService.mJobPackageTracker, mContext.getMainLooper())); @@ -655,13 +661,13 @@ class JobConcurrencyManager { } preferredUidOnly.sort(sDeterminationComparator); stoppable.sort(sDeterminationComparator); - for (int i = numRunningJobs; i < MAX_JOB_CONTEXTS_COUNT; ++i) { + for (int i = numRunningJobs; i < STANDARD_CONCURRENCY_LIMIT; ++i) { final JobServiceContext jsc; final int numIdleContexts = mIdleContexts.size(); if (numIdleContexts > 0) { jsc = mIdleContexts.removeAt(numIdleContexts - 1); } else { - Slog.wtf(TAG, "Had fewer than " + MAX_JOB_CONTEXTS_COUNT + " in existence"); + Slog.wtf(TAG, "Had fewer than " + STANDARD_CONCURRENCY_LIMIT + " in existence"); jsc = createNewJobServiceContext(); } @@ -681,6 +687,7 @@ class JobConcurrencyManager { JobStatus nextPending; pendingJobQueue.resetIterator(); + int projectedRunningCount = numRunningJobs; while ((nextPending = pendingJobQueue.next()) != null) { if (mRunningJobs.contains(nextPending)) { continue; @@ -694,6 +701,9 @@ class JobConcurrencyManager { ContextAssignment selectedContext = null; final int allWorkTypes = getJobWorkTypes(nextPending); final boolean pkgConcurrencyOkay = !isPkgConcurrencyLimitedLocked(nextPending); + final boolean isTopEj = nextPending.shouldTreatAsExpeditedJob() + && nextPending.lastEvaluatedBias == JobInfo.BIAS_TOP_APP; + final boolean isInOverage = projectedRunningCount > STANDARD_CONCURRENCY_LIMIT; boolean startingJob = false; if (idle.size() > 0) { final int idx = idle.size() - 1; @@ -711,14 +721,36 @@ class JobConcurrencyManager { assignment.newWorkType = workType; } } - if (selectedContext == null) { + if (selectedContext == null && stoppable.size() > 0) { + int topEjCount = 0; + for (int r = mRunningJobs.size() - 1; r >= 0; --r) { + JobStatus js = mRunningJobs.valueAt(r); + if (js.startedAsExpeditedJob && js.lastEvaluatedBias == JobInfo.BIAS_TOP_APP) { + topEjCount++; + } + } for (int s = stoppable.size() - 1; s >= 0; --s) { final ContextAssignment assignment = stoppable.get(s); final JobStatus runningJob = assignment.context.getRunningJobLocked(); - // Maybe stop the job if it has had its day in the sun. Don't let a different - // app preempt jobs started for TOP apps though. - if (runningJob.lastEvaluatedBias < JobInfo.BIAS_TOP_APP - && assignment.shouldStopJobReason != null) { + // Maybe stop the job if it has had its day in the sun. Only allow replacing + // for one of the following conditions: + // 1. We're putting in the current TOP app's EJ + // 2. There aren't too many jobs running AND the current job started when the + // app was in the background + // 3. There aren't too many jobs running AND the current job started when the + // app was on TOP, but the app has since left TOP + // 4. There aren't too many jobs running AND the current job started when the + // app was on TOP, the app is still TOP, but there are too many TOP+EJs + // running (because we don't want them to starve out other apps and the + // current job has already run for the minimum guaranteed time). + boolean canReplace = isTopEj; // Case 1 + if (!canReplace && !isInOverage) { + final int currentJobBias = mService.evaluateJobBiasLocked(runningJob); + canReplace = runningJob.lastEvaluatedBias < JobInfo.BIAS_TOP_APP // Case 2 + || currentJobBias < JobInfo.BIAS_TOP_APP // Case 3 + || topEjCount > .5 * mWorkTypeConfig.getMaxTotal(); // Case 4 + } + if (canReplace) { int replaceWorkType = mWorkCountTracker.canJobStart(allWorkTypes, assignment.context.getRunningJobWorkType()); if (replaceWorkType != WORK_TYPE_NONE) { @@ -736,7 +768,7 @@ class JobConcurrencyManager { } } } - if (selectedContext == null) { + if (selectedContext == null && (!isInOverage || isTopEj)) { int lowestBiasSeen = Integer.MAX_VALUE; for (int p = preferredUidOnly.size() - 1; p >= 0; --p) { final ContextAssignment assignment = preferredUidOnly.get(p); @@ -765,10 +797,43 @@ class JobConcurrencyManager { preferredUidOnly.remove(selectedContext); } } + // Make sure to run EJs for the TOP app immediately. + if (isTopEj) { + if (selectedContext != null + && selectedContext.context.getRunningJobLocked() != null) { + // We're "replacing" a currently running job, but we want TOP EJs to start + // immediately, so we'll start the EJ on a fresh available context and + // stop this currently running job to replace in two steps. + changed.add(selectedContext); + projectedRunningCount--; + selectedContext.newJob = null; + selectedContext.newWorkType = WORK_TYPE_NONE; + selectedContext = null; + } + if (selectedContext == null) { + selectedContext = mContextAssignmentPool.acquire(); + if (selectedContext == null) { + selectedContext = new ContextAssignment(); + } + selectedContext.context = mIdleContexts.size() > 0 + ? mIdleContexts.removeAt(mIdleContexts.size() - 1) + : createNewJobServiceContext(); + selectedContext.newJob = nextPending; + final int workType = mWorkCountTracker.canJobStart(allWorkTypes); + selectedContext.newWorkType = + (workType != WORK_TYPE_NONE) ? workType : WORK_TYPE_TOP; + } + } final PackageStats packageStats = getPkgStatsLocked( nextPending.getSourceUserId(), nextPending.getSourcePackageName()); if (selectedContext != null) { changed.add(selectedContext); + if (selectedContext.context.getRunningJobLocked() != null) { + projectedRunningCount--; + } + if (selectedContext.newJob != null) { + projectedRunningCount++; + } packageStats.adjustStagedCount(true, nextPending.shouldTreatAsExpeditedJob()); } if (startingJob) { @@ -793,7 +858,7 @@ class JobConcurrencyManager { if (DEBUG) { Slog.d(TAG, "preempting job: " + js); } - // preferredUid will be set to uid of currently running job. + // preferredUid will be set to uid of currently running job, if appropriate. assignment.context.cancelExecutingJobLocked( assignment.preemptReasonCode, JobParameters.INTERNAL_STOP_REASON_PREEMPT, assignment.preemptReason); @@ -811,9 +876,6 @@ class JobConcurrencyManager { } for (int s = stoppable.size() - 1; s >= 0; --s) { final ContextAssignment assignment = stoppable.get(s); - // The preferred UID is set when we cancel with PREEMPT reason, but don't preserve the - // UID for any stoppable contexts since we want to open the context up to any/all apps. - assignment.context.clearPreferredUid(); assignment.clear(); mContextAssignmentPool.release(assignment); } @@ -838,6 +900,21 @@ class JobConcurrencyManager { } @GuardedBy("mLock") + void onUidBiasChangedLocked(int prevBias, int newBias) { + if (prevBias != JobInfo.BIAS_TOP_APP && newBias != JobInfo.BIAS_TOP_APP) { + // TOP app didn't change. Nothing to do. + return; + } + if (mService.getPendingJobQueue().size() == 0) { + // Nothing waiting for the top app to leave. Nothing to do. + return; + } + // Don't stop the TOP jobs directly. Instead, see if they would be replaced by some + // pending job (there may not always be something to replace them). + assignJobsToContextsLocked(); + } + + @GuardedBy("mLock") boolean stopJobOnServiceContextLocked(JobStatus job, @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) { if (!mRunningJobs.contains(job)) { @@ -1041,7 +1118,13 @@ class JobConcurrencyManager { mWorkCountTracker.onJobFinished(workType); mRunningJobs.remove(jobStatus); mActiveServices.remove(worker); - mIdleContexts.add(worker); + if (mIdleContexts.size() < MAX_RETAINED_OBJECTS) { + // Don't need to save all new contexts, but keep some extra around in case we need + // extras for another TOP+EJ overage. + mIdleContexts.add(worker); + } else { + mNumDroppedContexts++; + } final PackageStats packageStats = mActivePkgStats.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()); if (packageStats == null) { @@ -1054,6 +1137,14 @@ class JobConcurrencyManager { } } + if (mActiveServices.size() >= STANDARD_CONCURRENCY_LIMIT) { + worker.clearPreferredUid(); + // We're over the limit (because the TOP app scheduled a lot of EJs). Don't start + // running anything new until we get back below the limit. + noteConcurrency(); + return; + } + final PendingJobQueue pendingJobQueue = mService.getPendingJobQueue(); if (worker.getPreferredUid() != JobServiceContext.NO_PREFERRED_UID) { updateCounterConfigLocked(); @@ -1245,6 +1336,18 @@ class JobConcurrencyManager { } } else if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_EJ) > 0) { return "blocking " + workTypeToString(WORK_TYPE_EJ) + " queue"; + } else if (js.startedAsExpeditedJob && js.lastEvaluatedBias == JobInfo.BIAS_TOP_APP) { + // Try not to let TOP + EJ starve out other apps. + int topEjCount = 0; + for (int r = mRunningJobs.size() - 1; r >= 0; --r) { + JobStatus j = mRunningJobs.valueAt(r); + if (j.startedAsExpeditedJob && j.lastEvaluatedBias == JobInfo.BIAS_TOP_APP) { + topEjCount++; + } + } + if (topEjCount > .5 * mWorkTypeConfig.getMaxTotal()) { + return "prevent top EJ dominance"; + } } // No other pending EJs. Return null so we don't let regular jobs preempt an EJ. return null; @@ -1361,10 +1464,10 @@ class JobConcurrencyManager { CONFIG_LIMITS_SCREEN_OFF.low.update(properties); CONFIG_LIMITS_SCREEN_OFF.critical.update(properties); - // Package concurrency limits must in the range [1, MAX_JOB_CONTEXTS_COUNT]. - mPkgConcurrencyLimitEj = Math.max(1, Math.min(MAX_JOB_CONTEXTS_COUNT, + // Package concurrency limits must in the range [1, STANDARD_CONCURRENCY_LIMIT]. + mPkgConcurrencyLimitEj = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT, properties.getInt(KEY_PKG_CONCURRENCY_LIMIT_EJ, DEFAULT_PKG_CONCURRENCY_LIMIT_EJ))); - mPkgConcurrencyLimitRegular = Math.max(1, Math.min(MAX_JOB_CONTEXTS_COUNT, + mPkgConcurrencyLimitRegular = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT, properties.getInt( KEY_PKG_CONCURRENCY_LIMIT_REGULAR, DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR))); } @@ -1492,6 +1595,13 @@ class JobConcurrencyManager { jsc.dumpLocked(pw, nowElapsed); } pw.decreaseIndent(); + + if (mNumDroppedContexts > 0) { + pw.println(); + pw.print("Dropped "); + pw.print(mNumDroppedContexts); + pw.println(" contexts"); + } } public void dumpProtoLocked(ProtoOutputStream proto, long tag, long now, long nowRealtime) { @@ -1600,7 +1710,7 @@ class JobConcurrencyManager { WorkTypeConfig(@NonNull String configIdentifier, int defaultMaxTotal, List<Pair<Integer, Integer>> defaultMin, List<Pair<Integer, Integer>> defaultMax) { mConfigIdentifier = configIdentifier; - mDefaultMaxTotal = mMaxTotal = Math.min(defaultMaxTotal, MAX_JOB_CONTEXTS_COUNT); + mDefaultMaxTotal = mMaxTotal = Math.min(defaultMaxTotal, STANDARD_CONCURRENCY_LIMIT); int numReserved = 0; for (int i = defaultMin.size() - 1; i >= 0; --i) { mDefaultMinReservedSlots.put(defaultMin.get(i).first, defaultMin.get(i).second); @@ -1621,8 +1731,8 @@ class JobConcurrencyManager { } void update(@NonNull DeviceConfig.Properties properties) { - // Ensure total in the range [1, MAX_JOB_CONTEXTS_COUNT]. - mMaxTotal = Math.max(1, Math.min(MAX_JOB_CONTEXTS_COUNT, + // Ensure total in the range [1, STANDARD_CONCURRENCY_LIMIT]. + mMaxTotal = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT, properties.getInt(KEY_PREFIX_MAX_TOTAL + mConfigIdentifier, mDefaultMaxTotal))); mMaxAllowedSlots.clear(); 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 fd7d8aa75882..b25832c7d521 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -159,8 +159,6 @@ public class JobSchedulerService extends com.android.server.SystemService public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); public static final boolean DEBUG_STANDBY = DEBUG || false; - /** The maximum number of concurrent jobs we run at one time. */ - static final int MAX_JOB_CONTEXTS_COUNT = 16; /** The maximum number of jobs that we allow an app to schedule */ private static final int MAX_JOBS_PER_APP = 150; /** The number of the most recently completed jobs to keep track of for debugging purposes. */ @@ -1423,6 +1421,7 @@ public class JobSchedulerService extends com.android.server.SystemService for (int c = 0; c < mControllers.size(); ++c) { mControllers.get(c).onUidBiasChangedLocked(uid, prevBias, newBias); } + mConcurrencyManager.onUidBiasChangedLocked(prevBias, newBias); } } } diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java index 54e0a4c6663c..2a79ec4587fc 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -751,7 +751,8 @@ public final class JobServiceContext implements ServiceConnection { } } mParams.setStopReason(stopReasonCode, internalStopReasonCode, debugReason); - if (internalStopReasonCode == JobParameters.INTERNAL_STOP_REASON_PREEMPT) { + if (stopReasonCode == JobParameters.STOP_REASON_PREEMPT) { + // Only preserve the UID when we're preempting the job for another one of the same UID. mPreferredUid = mRunningJob != null ? mRunningJob.getUid() : NO_PREFERRED_UID; } handleCancelLocked(debugReason); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java index b3e81cb89e52..fdcd2fc82ecc 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java @@ -297,9 +297,9 @@ public final class QuotaController extends StateController { private final SparseBooleanArray mForegroundUids = new SparseBooleanArray(); /** - * List of jobs that started while the UID was in the TOP state. There will be no more than - * 16 ({@link JobSchedulerService#MAX_JOB_CONTEXTS_COUNT}) running at once, so an ArraySet is - * fine. + * List of jobs that started while the UID was in the TOP state. There will usually be no more + * than {@value JobConcurrencyManager#MAX_STANDARD_JOB_CONCURRENCY} running at once, so an + * ArraySet is fine. */ private final ArraySet<JobStatus> mTopStartedJobs = new ArraySet<>(); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java index fd6aa7a1d282..223091a27ee1 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java @@ -289,9 +289,9 @@ public class TareController extends StateController { }; /** - * List of jobs that started while the UID was in the TOP state. There will be no more than - * 16 ({@link JobSchedulerService#MAX_JOB_CONTEXTS_COUNT}) running at once, so an ArraySet is - * fine. + * List of jobs that started while the UID was in the TOP state. There will usually be no more + * than {@value JobConcurrencyManager#MAX_STANDARD_JOB_CONCURRENCY} running at once, so an + * ArraySet is fine. */ @GuardedBy("mLock") private final ArraySet<JobStatus> mTopStartedJobs = new ArraySet<>(); diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index b520102b2830..fde59ea1e5f3 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -1309,7 +1309,7 @@ public class AppStandbyController return STANDBY_BUCKET_WORKING_SET; } - if (mInjector.hasScheduleExactAlarm(packageName, UserHandle.getUid(userId, appId))) { + if (mInjector.hasExactAlarmPermission(packageName, UserHandle.getUid(userId, appId))) { return STANDBY_BUCKET_WORKING_SET; } } @@ -2326,8 +2326,8 @@ public class AppStandbyController return mWellbeingApp != null && mWellbeingApp.equals(packageName); } - boolean hasScheduleExactAlarm(String packageName, int uid) { - return mAlarmManagerInternal.hasScheduleExactAlarm(packageName, uid); + boolean hasExactAlarmPermission(String packageName, int uid) { + return mAlarmManagerInternal.hasExactAlarmPermission(packageName, uid); } void updatePowerWhitelistCache() { diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index f9317eba4e27..968be3e20791 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -1425,12 +1425,17 @@ void BootAnimation::drawTexturedQuad(float xStart, float yStart, float width, fl void BootAnimation::initDynamicColors() { for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) { - parseColorDecimalString( - android::base::GetProperty("persist.bootanim.color" + std::to_string(i + 1), ""), + const auto syspropName = "persist.bootanim.color" + std::to_string(i + 1); + const auto syspropValue = android::base::GetProperty(syspropName, ""); + if (syspropValue != "") { + SLOGI("Loaded dynamic color: %s -> %s", syspropName.c_str(), syspropValue.c_str()); + mDynamicColorsApplied = true; + } + parseColorDecimalString(syspropValue, mAnimation->endColors[i], mAnimation->startColors[i]); } glUseProgram(mImageShader); - SLOGI("[BootAnimation] Dynamically coloring boot animation."); + SLOGI("Dynamically coloring boot animation. Sysprops loaded? %i", mDynamicColorsApplied); for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) { float *startColor = mAnimation->startColors[i]; float *endColor = mAnimation->endColors[i]; @@ -1465,6 +1470,11 @@ bool BootAnimation::playAnimation(const Animation& animation) { continue; //to next part } + if (animation.dynamicColoringEnabled && part.useDynamicColoring && !mDynamicColorsApplied) { + SLOGD("Trying to load dynamic color sysprops."); + initDynamicColors(); + } + // process the part not only while the count allows but also if already fading for (int r=0 ; !part.count || r<part.count || fadedFramesCount > 0 ; r++) { if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break; diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index 4c378cbc48bd..a136ad0a90f2 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -228,6 +228,7 @@ private: bool mTimeIsAccurate; bool mTimeFormat12Hour; bool mShuttingDown; + bool mDynamicColorsApplied = false; String8 mZipFileName; SortedVector<String8> mLoadedFiles; sp<TimeCheckThread> mTimeCheckThread = nullptr; diff --git a/core/api/current.txt b/core/api/current.txt index 92c263624527..89ebf2773256 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -9225,6 +9225,7 @@ package android.content { field public static final int CLASSIFICATION_NOT_COMPLETE = 1; // 0x1 field public static final int CLASSIFICATION_NOT_PERFORMED = 2; // 0x2 field @NonNull public static final android.os.Parcelable.Creator<android.content.ClipDescription> CREATOR; + field public static final String EXTRA_IS_SENSITIVE = "android.content.extra.IS_SENSITIVE"; field public static final String MIMETYPE_TEXT_HTML = "text/html"; field public static final String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent"; field public static final String MIMETYPE_TEXT_PLAIN = "text/plain"; @@ -37577,10 +37578,12 @@ package android.security { public class KeyStoreException extends java.lang.Exception { method public int getNumericErrorCode(); + method public int getRetryPolicy(); method public boolean isSystemError(); method public boolean isTransientFailure(); method public boolean requiresUserAuthentication(); field public static final int ERROR_ATTESTATION_CHALLENGE_TOO_LARGE = 9; // 0x9 + field public static final int ERROR_ATTESTATION_KEYS_UNAVAILABLE = 16; // 0x10 field public static final int ERROR_ID_ATTESTATION_FAILURE = 8; // 0x8 field public static final int ERROR_INCORRECT_USAGE = 13; // 0xd field public static final int ERROR_INTERNAL_SYSTEM_ERROR = 4; // 0x4 @@ -37595,6 +37598,9 @@ package android.security { field public static final int ERROR_PERMISSION_DENIED = 5; // 0x5 field public static final int ERROR_UNIMPLEMENTED = 12; // 0xc field public static final int ERROR_USER_AUTHENTICATION_REQUIRED = 2; // 0x2 + field public static final int RETRY_NEVER = 1; // 0x1 + field public static final int RETRY_WHEN_CONNECTIVITY_AVAILABLE = 3; // 0x3 + field public static final int RETRY_WITH_EXPONENTIAL_BACKOFF = 2; // 0x2 } @Deprecated public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 381314e36e66..df5dcda6eb42 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -3262,10 +3262,6 @@ package android.window { field public static final int FEATURE_WINDOW_TOKENS = 2; // 0x2 } - public interface OnBackInvokedDispatcher { - field public static final long DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME = 195946584L; // 0xbade858L - } - public final class SplashScreenView extends android.widget.FrameLayout { method @Nullable public android.view.View getBrandingView(); } diff --git a/core/java/android/accessibilityservice/MagnificationConfig.java b/core/java/android/accessibilityservice/MagnificationConfig.java index 74c91d6097c3..ddafb224a5cd 100644 --- a/core/java/android/accessibilityservice/MagnificationConfig.java +++ b/core/java/android/accessibilityservice/MagnificationConfig.java @@ -42,9 +42,9 @@ import java.lang.annotation.RetentionPolicy; * </p> * * <p> - * When the magnification config uses {@link #MAGNIFICATION_MODE_WINDOW}. - * {@link AccessibilityService} will be able to control the activated window magnifier - * on the display. + * When the magnification config uses {@link #MAGNIFICATION_MODE_WINDOW} and the platform + * supports {@link android.content.pm.PackageManager#FEATURE_WINDOW_MAGNIFICATION} feature. + * {@link AccessibilityService} will be able to control window magnifier on the display. * </p> * * <p> @@ -57,9 +57,12 @@ public final class MagnificationConfig implements Parcelable { /** The controlling magnification mode. It controls the activated magnifier. */ public static final int MAGNIFICATION_MODE_DEFAULT = 0; - /** The controlling magnification mode. It controls fullscreen magnifier. */ + /** The controlling magnification mode. It controls full-screen magnifier. */ public static final int MAGNIFICATION_MODE_FULLSCREEN = 1; - /** The controlling magnification mode. It controls window magnifier. */ + /** + * The controlling magnification mode. It is valid if the platform supports + * {@link android.content.pm.PackageManager#FEATURE_WINDOW_MAGNIFICATION} feature. + */ public static final int MAGNIFICATION_MODE_WINDOW = 2; /** @hide */ diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 5e521b03f6e3..893dc2f6ace4 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -1209,7 +1209,9 @@ public final class UiAutomation { * @see android.view.WindowAnimationFrameStats * @see #getWindowAnimationFrameStats() * @see android.R.styleable#WindowAnimation - * @deprecated animation-frames are no-longer used. + * @deprecated animation-frames are no-longer used. Use Shared + * <a href="https://perfetto.dev/docs/data-sources/frametimeline">FrameTimeline</a> + * jank metrics instead. */ @Deprecated public void clearWindowAnimationFrameStats() { diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index 5c1ab3879487..e502ba03bf8e 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -222,9 +222,6 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu }) public @interface WindowConfig {} - /** @hide */ - public static final int PINNED_WINDOWING_MODE_ELEVATION_IN_DIP = 5; - @UnsupportedAppUsage public WindowConfiguration() { unset(); diff --git a/core/java/android/app/ambientcontext/IAmbientContextManager.aidl b/core/java/android/app/ambientcontext/IAmbientContextManager.aidl index 3b15bcb9846d..0d9ecfdfe8f6 100644 --- a/core/java/android/app/ambientcontext/IAmbientContextManager.aidl +++ b/core/java/android/app/ambientcontext/IAmbientContextManager.aidl @@ -25,7 +25,7 @@ import android.os.RemoteCallback; * * @hide */ -oneway interface IAmbientContextManager { +interface IAmbientContextManager { void registerObserver(in AmbientContextEventRequest request, in PendingIntent resultPendingIntent, in RemoteCallback statusCallback); @@ -33,4 +33,4 @@ oneway interface IAmbientContextManager { void queryServiceStatus(in int[] eventTypes, in String callingPackage, in RemoteCallback statusCallback); void startConsentActivity(in int[] eventTypes, in String callingPackage); -}
\ No newline at end of file +} diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl index e2859998efd4..8cfbf2faee67 100644 --- a/core/java/android/companion/virtual/IVirtualDevice.aidl +++ b/core/java/android/companion/virtual/IVirtualDevice.aidl @@ -17,7 +17,8 @@ package android.companion.virtual; import android.app.PendingIntent; -import android.companion.virtual.audio.IAudioSessionCallback; +import android.companion.virtual.audio.IAudioConfigChangedCallback; +import android.companion.virtual.audio.IAudioRoutingCallback; import android.graphics.Point; import android.graphics.PointF; import android.hardware.input.VirtualKeyEvent; @@ -51,7 +52,8 @@ interface IVirtualDevice { */ void onAudioSessionStarting( int displayId, - IAudioSessionCallback callback); + IAudioRoutingCallback routingCallback, + IAudioConfigChangedCallback configChangedCallback); void onAudioSessionEnded(); diff --git a/core/java/android/companion/virtual/audio/IAudioSessionCallback.aidl b/core/java/android/companion/virtual/audio/IAudioConfigChangedCallback.aidl index e22ce148a9be..47b5e940b27a 100644 --- a/core/java/android/companion/virtual/audio/IAudioSessionCallback.aidl +++ b/core/java/android/companion/virtual/audio/IAudioConfigChangedCallback.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. @@ -20,15 +20,11 @@ import android.media.AudioPlaybackConfiguration; import android.media.AudioRecordingConfiguration; /** - * Callback to control audio rerouting, notify playback and recording state of applications running - * on virtual device. + * Callback to notify playback and recording state of applications running on virtual device. * * @hide */ -oneway interface IAudioSessionCallback { - - /** Updates the set of applications that need to have their audio rerouted. */ - void onAppsNeedingAudioRoutingChanged(in int[] appUids); +oneway interface IAudioConfigChangedCallback { /** * Called whenever the playback configuration of applications running on virtual device has diff --git a/core/java/android/companion/virtual/audio/IAudioRoutingCallback.aidl b/core/java/android/companion/virtual/audio/IAudioRoutingCallback.aidl new file mode 100644 index 000000000000..a424d62266c9 --- /dev/null +++ b/core/java/android/companion/virtual/audio/IAudioRoutingCallback.aidl @@ -0,0 +1,28 @@ +/* + * 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.companion.virtual.audio; + +/** + * Callback to control audio rerouting for applications running on virtual device. + * + * @hide + */ +oneway interface IAudioRoutingCallback { + + /** Updates the set of applications that need to have their audio rerouted. */ + void onAppsNeedingAudioRoutingChanged(in int[] appUids); +} diff --git a/core/java/android/companion/virtual/audio/VirtualAudioDevice.java b/core/java/android/companion/virtual/audio/VirtualAudioDevice.java index 3f7299fbb09e..0db7b5fe8289 100644 --- a/core/java/android/companion/virtual/audio/VirtualAudioDevice.java +++ b/core/java/android/companion/virtual/audio/VirtualAudioDevice.java @@ -76,8 +76,8 @@ public final class VirtualAudioDevice implements Closeable { * @hide */ public VirtualAudioDevice(Context context, IVirtualDevice virtualDevice, - VirtualDisplay virtualDisplay, Executor executor, - AudioConfigurationChangeCallback callback) { + @NonNull VirtualDisplay virtualDisplay, @Nullable Executor executor, + @Nullable AudioConfigurationChangeCallback callback) { mContext = context; mVirtualDevice = virtualDevice; mVirtualDisplay = virtualDisplay; @@ -105,7 +105,8 @@ public final class VirtualAudioDevice implements Closeable { try { mVirtualDevice.onAudioSessionStarting(mVirtualDisplay.getDisplay().getDisplayId(), - /* callback= */ mOngoingSession); + /* routingCallback= */ mOngoingSession, + /* configChangedCallback= */ mOngoingSession.getAudioConfigChangedListener()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -135,7 +136,8 @@ public final class VirtualAudioDevice implements Closeable { try { mVirtualDevice.onAudioSessionStarting(mVirtualDisplay.getDisplay().getDisplayId(), - /* callback= */ mOngoingSession); + /* routingCallback= */ mOngoingSession, + /* configChangedCallback= */ mOngoingSession.getAudioConfigChangedListener()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/companion/virtual/audio/VirtualAudioSession.java b/core/java/android/companion/virtual/audio/VirtualAudioSession.java index 524f6e2ab063..321a1c57643b 100644 --- a/core/java/android/companion/virtual/audio/VirtualAudioSession.java +++ b/core/java/android/companion/virtual/audio/VirtualAudioSession.java @@ -50,16 +50,14 @@ import java.util.concurrent.Executor; * @hide */ @VisibleForTesting -public final class VirtualAudioSession extends IAudioSessionCallback.Stub implements +public final class VirtualAudioSession extends IAudioRoutingCallback.Stub implements UserRestrictionsCallback, Closeable { private static final String TAG = "VirtualAudioSession"; private final Context mContext; private final UserRestrictionsDetector mUserRestrictionsDetector; - /** The {@link Executor} for sending {@link AudioConfigurationChangeCallback} to the caller */ - private final Executor mExecutor; @Nullable - private final AudioConfigurationChangeCallback mCallback; + private final AudioConfigChangedCallback mAudioConfigChangedCallback; private final Object mLock = new Object(); @GuardedBy("mLock") private final IntArray mReroutedAppUids = new IntArray(); @@ -73,13 +71,44 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem @GuardedBy("mLock") private AudioInjection mAudioInjection; + /** + * Class to receive {@link IAudioConfigChangedCallback} callbacks from service. + * + * @hide + */ + @VisibleForTesting + public static final class AudioConfigChangedCallback extends IAudioConfigChangedCallback.Stub { + private final Executor mExecutor; + private final AudioConfigurationChangeCallback mCallback; + + AudioConfigChangedCallback(Context context, Executor executor, + AudioConfigurationChangeCallback callback) { + mExecutor = executor != null ? executor : context.getMainExecutor(); + mCallback = callback; + } + + @Override + public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) { + if (mCallback != null) { + mExecutor.execute(() -> mCallback.onPlaybackConfigChanged(configs)); + } + } + + @Override + public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) { + if (mCallback != null) { + mExecutor.execute(() -> mCallback.onRecordingConfigChanged(configs)); + } + } + } + @VisibleForTesting public VirtualAudioSession(Context context, @Nullable AudioConfigurationChangeCallback callback, @Nullable Executor executor) { mContext = context; mUserRestrictionsDetector = new UserRestrictionsDetector(context); - mCallback = callback; - mExecutor = executor != null ? executor : context.getMainExecutor(); + mAudioConfigChangedCallback = callback == null ? null : new AudioConfigChangedCallback( + context, executor, callback); } /** @@ -132,6 +161,13 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem /** @hide */ @VisibleForTesting @Nullable + public AudioConfigChangedCallback getAudioConfigChangedListener() { + return mAudioConfigChangedCallback; + } + + /** @hide */ + @VisibleForTesting + @Nullable public AudioCapture getAudioCapture() { synchronized (mLock) { return mAudioCapture; @@ -263,20 +299,6 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem } } - @Override - public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) { - if (mCallback != null) { - mExecutor.execute(() -> mCallback.onPlaybackConfigChanged(configs)); - } - } - - @Override - public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) { - if (mCallback != null) { - mExecutor.execute(() -> mCallback.onRecordingConfigChanged(configs)); - } - } - /** @hide */ @VisibleForTesting public IntArray getReroutedAppUids() { diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java index 2ecd71bc1f06..bf466116009b 100644 --- a/core/java/android/content/ClipDescription.java +++ b/core/java/android/content/ClipDescription.java @@ -134,6 +134,26 @@ public class ClipDescription implements Parcelable { public static final String EXTRA_LOGGING_INSTANCE_ID = "android.intent.extra.LOGGING_INSTANCE_ID"; + /** + * Indicates that a ClipData contains potentially sensitive information, such as a + * password or credit card number. + * <p> + * Type: boolean + * </p> + * <p> + * This extra can be used to indicate that a ClipData contains sensitive information that + * should be redacted or hidden from view until a user takes explicit action to reveal it + * (e.g., by pasting). + * </p> + * <p> + * Adding this extra does not change clipboard behavior or add additional security to + * the ClipData. Its purpose is essentially a rendering hint from the source application, + * asking that the data within be obfuscated or redacted, unless the user has taken action + * to make it visible. + * </p> + */ + public static final String EXTRA_IS_SENSITIVE = "android.content.extra.IS_SENSITIVE"; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(value = diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 227ac1a02890..a90f6d625c51 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -4188,6 +4188,8 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device * supports window magnification. + * + * @see android.accessibilityservice.MagnificationConfig#MAGNIFICATION_MODE_WINDOW */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_WINDOW_MAGNIFICATION = diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS index 8e5ed8f6e578..1f3108a1f04b 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -66,3 +66,6 @@ per-file *UpdateEngine* = file:/platform/system/update_engine:/OWNERS # VINTF per-file Vintf* = file:/platform/system/libvintf:/OWNERS + +# Tracing +per-file Trace.java = file:/TRACE_OWNERS diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java index a4f6004a288a..ac2156e9e46e 100644 --- a/core/java/android/os/Trace.java +++ b/core/java/android/os/Trace.java @@ -136,6 +136,12 @@ public final class Trace { @FastNative private static native void nativeAsyncTraceEnd(long tag, String name, int cookie); @FastNative + private static native void nativeAsyncTraceForTrackBegin(long tag, + String trackName, String name, int cookie); + @FastNative + private static native void nativeAsyncTraceForTrackEnd(long tag, + String trackName, String name, int cookie); + @FastNative private static native void nativeInstant(long tag, String name); @FastNative private static native void nativeInstantForTrack(long tag, String trackName, String name); @@ -271,6 +277,47 @@ public final class Trace { } } + + /** + * Writes a trace message to indicate that a given section of code has + * begun. Must be followed by a call to {@link #asyncTraceForTrackEnd} using the same + * tag. This function operates exactly like {@link #asyncTraceBegin(long, String, int)}, + * except with the inclusion of a track name argument for where this method should appear. + * + * @param traceTag The trace tag. + * @param trackName The track where the event should appear in the trace. + * @param methodName The method name to appear in the trace. + * @param cookie Unique identifier for distinguishing simultaneous events + * + * @hide + */ + public static void asyncTraceForTrackBegin(long traceTag, + @NonNull String trackName, @NonNull String methodName, int cookie) { + if (isTagEnabled(traceTag)) { + nativeAsyncTraceForTrackBegin(traceTag, trackName, methodName, cookie); + } + } + + /** + * Writes a trace message to indicate that the current method has ended. + * Must be called exactly once for each call to + * {@link #asyncTraceForTrackBegin(long, String, String, int)} + * using the same tag, track name, name and cookie. + * + * @param traceTag The trace tag. + * @param trackName The track where the event should appear in the trace. + * @param methodName The method name to appear in the trace. + * @param cookie Unique identifier for distinguishing simultaneous events + * + * @hide + */ + public static void asyncTraceForTrackEnd(long traceTag, + @NonNull String trackName, @NonNull String methodName, int cookie) { + if (isTagEnabled(traceTag)) { + nativeAsyncTraceForTrackEnd(traceTag, trackName, methodName, cookie); + } + } + /** * Writes a trace message to indicate that a given section of code was invoked. * diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 7dc4f22000b8..9591e4125ee7 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -8093,14 +8093,17 @@ public final class ViewRootImpl implements ViewParent, private void setFrame(Rect frame) { mWinFrame.set(frame); + final WindowConfiguration winConfig = getConfiguration().windowConfiguration; + mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop() + ? winConfig.getMaxBounds() + : frame); // Surface position is now inherited from parent, and BackdropFrameRenderer uses backdrop // frame to position content. Thus, we just keep the size of backdrop frame, and remove the // offset to avoid double offset from display origin. - mPendingBackDropFrame.set(frame); mPendingBackDropFrame.offsetTo(0, 0); mInsetsController.onFrameChanged(mOverrideInsetsFrame != null ? - mOverrideInsetsFrame : frame); + mOverrideInsetsFrame : frame); } /** diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index cde1cc704f92..ba3417980a3d 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -517,6 +517,13 @@ public final class WindowInsets { /** * Returns the {@link Rect} of the maximum bounds of the system privacy indicator, for the * current orientation, in relative coordinates, or null if the bounds have not been loaded yet. + * <p> + * The privacy indicator bounds are determined by SystemUI, and subsequently loaded once the + * StatusBar window has been created and attached. The bounds for all rotations are calculated + * and loaded at once, and this value is only expected to ever change on display or font scale + * changes. As long as there is a StatusBar window, this value should not be expected to be + * null. + * <p> * The privacy indicator shows over apps when an app uses the microphone or camera permissions, * while an app is in immersive mode. * diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java index 01acdfec6c27..9fc7b07200ae 100644 --- a/core/java/android/view/translation/UiTranslationManager.java +++ b/core/java/android/view/translation/UiTranslationManager.java @@ -163,7 +163,6 @@ public final class UiTranslationManager { /** * @removed Use {@link #startTranslation(TranslationSpec, TranslationSpec, List, ActivityId, * UiTranslationSpec)} instead. - * * @hide */ @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) @@ -180,13 +179,13 @@ public final class UiTranslationManager { /** * Request ui translation for a given Views. * - * @param sourceSpec {@link TranslationSpec} for the data to be translated. - * @param targetSpec {@link TranslationSpec} for the translated data. - * @param viewIds A list of the {@link View}'s {@link AutofillId} which needs to be translated - * @param activityId the identifier for the Activity which needs ui translation + * @param sourceSpec {@link TranslationSpec} for the data to be translated. + * @param targetSpec {@link TranslationSpec} for the translated data. + * @param viewIds A list of the {@link View}'s {@link AutofillId} which needs to be + * translated + * @param activityId the identifier for the Activity which needs ui translation * @param uiTranslationSpec configuration for translation of the specified views * @throws IllegalArgumentException if the no {@link View}'s {@link AutofillId} in the list - * * @hide */ @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) @@ -220,8 +219,7 @@ public final class UiTranslationManager { * * @param activityId the identifier for the Activity which needs ui translation * @throws NullPointerException the activityId or - * {@link android.app.assist.ActivityId#getToken()} is {@code null} - * + * {@link android.app.assist.ActivityId#getToken()} is {@code null} * @hide */ @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) @@ -245,8 +243,7 @@ public final class UiTranslationManager { * * @param activityId the identifier for the Activity which needs ui translation * @throws NullPointerException the activityId or - * {@link android.app.assist.ActivityId#getToken()} is {@code null} - * + * {@link android.app.assist.ActivityId#getToken()} is {@code null} * @hide */ @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) @@ -270,8 +267,7 @@ public final class UiTranslationManager { * * @param activityId the identifier for the Activity which needs ui translation * @throws NullPointerException the activityId or - * {@link android.app.assist.ActivityId#getToken()} is {@code null} - * + * {@link android.app.assist.ActivityId#getToken()} is {@code null} * @hide */ @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) @@ -290,20 +286,29 @@ public final class UiTranslationManager { } /** - * Register for notifications of UI Translation state changes on the foreground activity. This + * Register for notifications of UI Translation state changes on the foreground Activity. This * is available to the owning application itself and also the current input method. * <p> * The application whose UI is being translated can use this to customize the UI Translation * behavior in ways that aren't made easy by methods like * {@link View#onCreateViewTranslationRequest(int[], Consumer)}. - * * <p> * Input methods can use this to offer complementary features to UI Translation; for example, * enabling outgoing message translation when the system is translating incoming messages in a * communication app. + * <p> + * Starting from {@link android.os.Build.VERSION_CODES#TIRAMISU}, if Activities are already + * being translated when a callback is registered, methods on the callback will be invoked for + * each translated activity, depending on the state of translation: + * <ul> + * <li>If translation is <em>not</em> paused, + * {@link UiTranslationStateCallback#onStarted} will be invoked.</li> + * <li>If translation <em>is</em> paused, {@link UiTranslationStateCallback#onStarted} + * will first be invoked, followed by {@link UiTranslationStateCallback#onPaused}.</li> + * </ul> * * @param callback the callback to register for receiving the state change - * notifications + * notifications */ public void registerUiTranslationStateCallback( @NonNull @CallbackExecutor Executor executor, @@ -355,9 +360,8 @@ public final class UiTranslationManager { * called or Activity is destroyed. * * @param activityDestroyed if the ui translation is finished because of activity destroyed. - * @param activityId the identifier for the Activity which needs ui translation - * @param componentName the ui translated Activity componentName. - * + * @param activityId the identifier for the Activity which needs ui translation + * @param componentName the ui translated Activity componentName. * @hide */ public void onTranslationFinished(boolean activityDestroyed, ActivityId activityId, diff --git a/core/java/android/window/OnBackInvokedDispatcher.java b/core/java/android/window/OnBackInvokedDispatcher.java index 5eed8cde8c7c..c254a9df3b4c 100644 --- a/core/java/android/window/OnBackInvokedDispatcher.java +++ b/core/java/android/window/OnBackInvokedDispatcher.java @@ -21,9 +21,6 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; -import android.annotation.TestApi; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; import android.os.Build; import java.lang.annotation.Retention; @@ -38,23 +35,6 @@ import java.lang.annotation.RetentionPolicy; * target (a.k.a. the callback to be invoked next), or its behavior. */ public interface OnBackInvokedDispatcher { - /** - * Enables dispatching the "back" action via {@link OnBackInvokedDispatcher}. - * - * When enabled, the following APIs are no longer invoked: - * <ul> - * <li> {@link android.app.Activity#onBackPressed} - * <li> {@link android.app.Dialog#onBackPressed} - * <li> {@link android.view.KeyEvent#KEYCODE_BACK} is no longer dispatched. - * </ul> - * - * @hide - */ - @TestApi - @ChangeId - @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) - long DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME = 195946584L; - /** @hide */ String TAG = "OnBackInvokedDispatcher"; diff --git a/core/java/android/window/PictureInPictureSurfaceTransaction.java b/core/java/android/window/PictureInPictureSurfaceTransaction.java index 2bf2f3193789..0a751c38cfff 100644 --- a/core/java/android/window/PictureInPictureSurfaceTransaction.java +++ b/core/java/android/window/PictureInPictureSurfaceTransaction.java @@ -47,6 +47,8 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { public final float mCornerRadius; + public final float mShadowRadius; + private final Rect mWindowCrop; private PictureInPictureSurfaceTransaction(Parcel in) { @@ -56,11 +58,12 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { in.readFloatArray(mFloat9); mRotation = in.readFloat(); mCornerRadius = in.readFloat(); + mShadowRadius = in.readFloat(); mWindowCrop = in.readTypedObject(Rect.CREATOR); } private PictureInPictureSurfaceTransaction(float alpha, @Nullable PointF position, - @Nullable float[] float9, float rotation, float cornerRadius, + @Nullable float[] float9, float rotation, float cornerRadius, float shadowRadius, @Nullable Rect windowCrop) { mAlpha = alpha; mPosition = position; @@ -73,12 +76,14 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { mRotation = rotation; } mCornerRadius = cornerRadius; + mShadowRadius = shadowRadius; mWindowCrop = (windowCrop == null) ? null : new Rect(windowCrop); } public PictureInPictureSurfaceTransaction(PictureInPictureSurfaceTransaction other) { this(other.mAlpha, other.mPosition, - other.mFloat9, other.mRotation, other.mCornerRadius, other.mWindowCrop); + other.mFloat9, other.mRotation, other.mCornerRadius, other.mShadowRadius, + other.mWindowCrop); } /** @return {@link Matrix} from {@link #mFloat9} */ @@ -93,6 +98,11 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { return mCornerRadius > 0; } + /** @return {@code true} if this transaction contains setting shadow radius. */ + public boolean hasShadowRadiusSet() { + return mShadowRadius > 0; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -103,13 +113,14 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { && Arrays.equals(mFloat9, that.mFloat9) && Objects.equals(mRotation, that.mRotation) && Objects.equals(mCornerRadius, that.mCornerRadius) + && Objects.equals(mShadowRadius, that.mShadowRadius) && Objects.equals(mWindowCrop, that.mWindowCrop); } @Override public int hashCode() { return Objects.hash(mAlpha, mPosition, Arrays.hashCode(mFloat9), - mRotation, mCornerRadius, mWindowCrop); + mRotation, mCornerRadius, mShadowRadius, mWindowCrop); } @Override @@ -124,6 +135,7 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { out.writeFloatArray(mFloat9); out.writeFloat(mRotation); out.writeFloat(mCornerRadius); + out.writeFloat(mShadowRadius); out.writeTypedObject(mWindowCrop, 0 /* flags */); } @@ -136,6 +148,7 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { + " matrix=" + matrix.toShortString() + " rotation=" + mRotation + " cornerRadius=" + mCornerRadius + + " shadowRadius=" + mShadowRadius + " crop=" + mWindowCrop + ")"; } @@ -156,6 +169,9 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { if (surfaceTransaction.hasCornerRadiusSet()) { tx.setCornerRadius(surfaceControl, surfaceTransaction.mCornerRadius); } + if (surfaceTransaction.hasShadowRadiusSet()) { + tx.setShadowRadius(surfaceControl, surfaceTransaction.mShadowRadius); + } if (surfaceTransaction.mAlpha != NOT_SET) { tx.setAlpha(surfaceControl, surfaceTransaction.mAlpha); } @@ -178,6 +194,7 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { private float[] mFloat9; private float mRotation; private float mCornerRadius = NOT_SET; + private float mShadowRadius = NOT_SET; private Rect mWindowCrop; public Builder setAlpha(float alpha) { @@ -201,6 +218,11 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { return this; } + public Builder setShadowRadius(float shadowRadius) { + mShadowRadius = shadowRadius; + return this; + } + public Builder setWindowCrop(@NonNull Rect windowCrop) { mWindowCrop = new Rect(windowCrop); return this; @@ -208,7 +230,7 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { public PictureInPictureSurfaceTransaction build() { return new PictureInPictureSurfaceTransaction(mAlpha, mPosition, - mFloat9, mRotation, mCornerRadius, mWindowCrop); + mFloat9, mRotation, mCornerRadius, mShadowRadius, mWindowCrop); } } } diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java index e0bee96002b8..8811116b25ad 100644 --- a/core/java/android/window/WindowOnBackInvokedDispatcher.java +++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java @@ -18,7 +18,6 @@ package android.window; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.compat.CompatChanges; import android.content.Context; import android.os.Debug; import android.os.Handler; @@ -253,21 +252,20 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { * {@link OnBackInvokedCallback}. */ public static boolean isOnBackInvokedCallbackEnabled(@Nullable Context context) { - // new back is enabled if the app targets T AND the feature flag is enabled AND the app - // does not explicitly request legacy back. - boolean targetsT = CompatChanges.isChangeEnabled(DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME); + // new back is enabled if the feature flag is enabled AND the app does not explicitly + // request legacy back. boolean featureFlagEnabled = IS_BACK_PREDICTABILITY_ENABLED; // If the context is null, we assume true and fallback on the two other conditions. - boolean appRequestsLegacy = - context == null || !context.getApplicationInfo().isOnBackInvokedCallbackEnabled(); + boolean appRequestsPredictiveBack = + context != null && context.getApplicationInfo().isOnBackInvokedCallbackEnabled(); if (DEBUG) { - Log.d(TAG, TextUtils.formatSimple("App: %s isChangeEnabled=%s featureFlagEnabled=%s " - + "onBackInvokedEnabled=%s", + Log.d(TAG, TextUtils.formatSimple("App: %s featureFlagEnabled=%s " + + "appRequestsPredictiveBack=%s", context != null ? context.getApplicationInfo().packageName : "null context", - targetsT, featureFlagEnabled, !appRequestsLegacy)); + featureFlagEnabled, appRequestsPredictiveBack)); } - return targetsT && featureFlagEnabled && !appRequestsLegacy; + return featureFlagEnabled && appRequestsPredictiveBack; } } diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index a316669aa516..88089b5b85f2 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -1158,9 +1158,7 @@ public class ChooserActivity extends ResolverActivity implements -1); // Action bar is user-independent, always start as primary safelyStartActivityAsUser(ti, getPersonalProfileUserHandle()); - if (!mAwaitingDelegateResponse) { - finish(); - } + finish(); } ); b.setId(R.id.chooser_nearby_button); @@ -1182,9 +1180,7 @@ public class ChooserActivity extends ResolverActivity implements -1); // Action bar is user-independent, always start as primary safelyStartActivityAsUser(ti, getPersonalProfileUserHandle()); - if (!mAwaitingDelegateResponse) { - finish(); - } + finish(); } ); b.setId(R.id.chooser_edit_button); @@ -2231,9 +2227,7 @@ public class ChooserActivity extends ResolverActivity implements TargetInfo clonedTarget = selectedTarget.cloneFilledIn(matchingIntent, 0); if (super.onTargetSelected(clonedTarget, false)) { updateModelAndChooserCounts(clonedTarget); - if (!mAwaitingDelegateResponse) { - finish(); - } + finish(); return; } } diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 1815ca69a55c..ea8589bddabb 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -210,7 +210,7 @@ public class ResolverActivity extends Activity implements private UserHandle mWorkProfileUserHandle; - protected boolean mAwaitingDelegateResponse; + /** * Get the string resource to be used as a label for the link to the resolver activity for an @@ -328,86 +328,6 @@ public class ResolverActivity extends Activity implements super.onCreate(savedInstanceState); } - /** - * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode - * where we hand over to the unbundled chooser (while violating many of the invariants of a - * typical ResolverActivity implementation). Subclasses running in this mode need to be able - * to opt-out of the normal ResolverActivity behavior. - * - * TODO: this should be removed later on in the unbundling migration, when the springboard - * activity no longer needs to derive from ResolverActivity. The hold-over design here is - * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as - * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity - * implementations that depend on the invariants that are violated in the headless mode). If - * necessary, we could instead consider using a springboard-only activity on the system side - * immediately, which would delegate either to the unbundled chooser, or to a - * (properly-inheriting) system ChooserActivity. This would have performance implications even - * when the unbundling experiment is disabled. - */ - protected void super_onRestart() { - super.onRestart(); - } - - /** - * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode - * where we hand over to the unbundled chooser (while violating many of the invariants of a - * typical ResolverActivity implementation). Subclasses running in this mode need to be able - * to opt-out of the normal ResolverActivity behavior. - * - * TODO: this should be removed later on in the unbundling migration, when the springboard - * activity no longer needs to derive from ResolverActivity. The hold-over design here is - * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as - * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity - * implementations that depend on the invariants that are violated in the headless mode). If - * necessary, we could instead consider using a springboard-only activity on the system side - * immediately, which would delegate either to the unbundled chooser, or to a - * (properly-inheriting) system ChooserActivity. This would have performance implications even - * when the unbundling experiment is disabled. - */ - protected void super_onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - } - - /** - * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode - * where we hand over to the unbundled chooser (while violating many of the invariants of a - * typical ResolverActivity implementation). Subclasses running in this mode need to be able - * to opt-out of the normal ResolverActivity behavior. - * - * TODO: this should be removed later on in the unbundling migration, when the springboard - * activity no longer needs to derive from ResolverActivity. The hold-over design here is - * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as - * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity - * implementations that depend on the invariants that are violated in the headless mode). If - * necessary, we could instead consider using a springboard-only activity on the system side - * immediately, which would delegate either to the unbundled chooser, or to a - * (properly-inheriting) system ChooserActivity. This would have performance implications even - * when the unbundling experiment is disabled. - */ - protected void super_onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - } - - /** - * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode - * where we hand over to the unbundled chooser (while violating many of the invariants of a - * typical ResolverActivity implementation). Subclasses running in this mode need to be able - * to opt-out of the normal ResolverActivity behavior. - * - * TODO: this should be removed later on in the unbundling migration, when the springboard - * activity no longer needs to derive from ResolverActivity. The hold-over design here is - * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as - * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity - * implementations that depend on the invariants that are violated in the headless mode). If - * necessary, we could instead consider using a springboard-only activity on the system side - * immediately, which would delegate either to the unbundled chooser, or to a - * (properly-inheriting) system ChooserActivity. This would have performance implications even - * when the unbundling experiment is disabled. - */ - public void super_onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - } - @Override protected void onCreate(Bundle savedInstanceState) { // Use a specialized prompt when we're handling the 'Home' app startActivity() @@ -682,9 +602,7 @@ public class ResolverActivity extends Activity implements mProfileSwitchMessage = null; onTargetSelected(dri, false); - if (!mAwaitingDelegateResponse) { - finish(); - } + finish(); } /** @@ -974,7 +892,7 @@ public class ResolverActivity extends Activity implements } final Intent intent = getIntent(); if ((intent.getFlags() & FLAG_ACTIVITY_NEW_TASK) != 0 && !isVoiceInteraction() - && !mResolvingHome && !mRetainInOnStop && !mAwaitingDelegateResponse) { + && !mResolvingHome && !mRetainInOnStop) { // This resolver is in the unusual situation where it has been // launched at the top of a new task. We don't let it be added // to the recent tasks shown to the user, and we need to make sure @@ -1143,9 +1061,7 @@ public class ResolverActivity extends Activity implements mMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem() ? MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_APP_FEATURED : MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_NONE_FEATURED); - if (!mAwaitingDelegateResponse) { - finish(); - } + finish(); } } @@ -2365,9 +2281,7 @@ public class ResolverActivity extends Activity implements .getItem(selections[0].getIndex()); if (ra.onTargetSelected(ti, false)) { ra.mPickOptionRequest = null; - if (!ra.mAwaitingDelegateResponse) { - ra.finish(); - } + ra.finish(); } } } diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index 0ada13a73ad2..f19bfc669997 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -514,9 +514,10 @@ public final class SystemUiDeviceConfigFlags { "is_nearby_share_first_target_in_ranked_app"; /** - * (boolean) Whether to enable the new unbundled "delegate chooser" implementation. + * (boolean) Whether to enable the new unbundled sharesheet + * (com.android.intentresolver.ChooserActivity). */ - public static final String USE_DELEGATE_CHOOSER = "use_delegate_chooser"; + public static final String USE_UNBUNDLED_SHARESHEET = "use_unbundled_sharesheet"; /** * (string) Name of the default QR code scanner activity. On the eligible devices this activity diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 89ac72255306..13ebe3c4dbb7 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -16,9 +16,7 @@ package com.android.internal.policy; -import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.N; @@ -2549,9 +2547,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind // Convert the DP elevation into physical pixels. elevation = dipToPx(elevation); mElevationAdjustedForStack = true; - } else if (windowingMode == WINDOWING_MODE_PINNED) { - elevation = dipToPx(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP); - mElevationAdjustedForStack = true; } else { mElevationAdjustedForStack = false; } diff --git a/core/jni/OWNERS b/core/jni/OWNERS index 2a4f812eb1de..9e5f6ea666ba 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -59,6 +59,7 @@ per-file android_media_* = file:/media/java/android/media/OWNERS per-file android_media_midi_* = file:/media/java/android/media/midi/OWNERS per-file android_opengl_* = file:/opengl/java/android/opengl/OWNERS per-file android_os_storage_* = file:/core/java/android/os/storage/OWNERS +per-file android_os_Trace* = file:/TRACE_OWNERS per-file android_se_* = file:/omapi/java/android/se/OWNERS per-file android_security_* = file:/core/java/android/security/OWNERS per-file android_view_* = file:/core/java/android/view/OWNERS diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp index 24d35316ef20..eab4e1d744cf 100644 --- a/core/jni/android_hardware_input_InputApplicationHandle.cpp +++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp @@ -105,10 +105,11 @@ std::shared_ptr<InputApplicationHandle> android_view_InputApplicationHandle_getH jobject android_view_InputApplicationHandle_fromInputApplicationInfo( JNIEnv* env, gui::InputApplicationInfo inputApplicationInfo) { - jobject binderObject = javaObjectForIBinder(env, inputApplicationInfo.token); + ScopedLocalRef<jobject> binderObject(env, + javaObjectForIBinder(env, inputApplicationInfo.token)); ScopedLocalRef<jstring> name(env, env->NewStringUTF(inputApplicationInfo.name.data())); return env->NewObject(gInputApplicationHandleClassInfo.clazz, - gInputApplicationHandleClassInfo.ctor, binderObject, name.get(), + gInputApplicationHandleClassInfo.ctor, binderObject.get(), name.get(), inputApplicationInfo.dispatchingTimeoutMillis); } diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp index db92310f2a26..484d92820b86 100644 --- a/core/jni/android_hardware_input_InputWindowHandle.cpp +++ b/core/jni/android_hardware_input_InputWindowHandle.cpp @@ -261,8 +261,8 @@ jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowIn } LOG_ALWAYS_FATAL_IF(inputWindowHandle == nullptr, "Failed to create new InputWindowHandle object."); - env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.token, - javaObjectForIBinder(env, windowInfo.token)); + ScopedLocalRef<jobject> token(env, javaObjectForIBinder(env, windowInfo.token)); + env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.token, token.get()); ScopedLocalRef<jstring> name(env, env->NewStringUTF(windowInfo.name.data())); env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.name, name.get()); env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsFlags, @@ -317,8 +317,9 @@ jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowIn ScopedLocalRef<jobject> matrixObj(env, AMatrix_newInstance(env, transformVals)); env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.transform, matrixObj.get()); + ScopedLocalRef<jobject> windowToken(env, javaObjectForIBinder(env, windowInfo.windowToken)); env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.windowToken, - javaObjectForIBinder(env, windowInfo.windowToken)); + windowToken.get()); return inputWindowHandle; } diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp index 85fd5d99e473..734b6ca47660 100644 --- a/core/jni/android_os_Trace.cpp +++ b/core/jni/android_os_Trace.cpp @@ -82,6 +82,26 @@ static void android_os_Trace_nativeAsyncTraceEnd(JNIEnv* env, jclass, }); } +static void android_os_Trace_nativeAsyncTraceForTrackBegin(JNIEnv* env, jclass, jlong tag, + jstring trackStr, jstring nameStr, + jint cookie) { + withString(env, trackStr, [env, tag, nameStr, cookie](char* track) { + withString(env, nameStr, [tag, track, cookie](char* name) { + atrace_async_for_track_begin(tag, track, name, cookie); + }); + }); +} + +static void android_os_Trace_nativeAsyncTraceForTrackEnd(JNIEnv* env, jclass, jlong tag, + jstring trackStr, jstring nameStr, + jint cookie) { + withString(env, trackStr, [env, tag, nameStr, cookie](char* track) { + withString(env, nameStr, [tag, track, cookie](char* name) { + atrace_async_for_track_end(tag, track, name, cookie); + }); + }); +} + static void android_os_Trace_nativeSetAppTracingAllowed(JNIEnv*, jclass, jboolean allowed) { atrace_update_tags(); } @@ -132,6 +152,12 @@ static const JNINativeMethod gTraceMethods[] = { { "nativeAsyncTraceEnd", "(JLjava/lang/String;I)V", (void*)android_os_Trace_nativeAsyncTraceEnd }, + { "nativeAsyncTraceForTrackBegin", + "(JLjava/lang/String;Ljava/lang/String;I)V", + (void*)android_os_Trace_nativeAsyncTraceForTrackBegin }, + { "nativeAsyncTraceForTrackEnd", + "(JLjava/lang/String;Ljava/lang/String;I)V", + (void*)android_os_Trace_nativeAsyncTraceForTrackEnd }, { "nativeInstant", "(JLjava/lang/String;)V", (void*)android_os_Trace_nativeInstant }, diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index e1b7a0c08cb3..fa58a71f25b9 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2729,6 +2729,11 @@ <!-- Whether force to enable telephony new data stack or not --> <bool name="config_force_enable_telephony_new_data_stack">true</bool> + <!-- Whether to adopt the predefined handover policies for IWLAN. + {@see CarrierConfigManager#KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY} + --> + <bool name="config_enable_iwlan_handover_policy">true</bool> + <!-- Whether WiFi display is supported by this device. There are many prerequisites for this feature to work correctly. Here are a few of them: @@ -4105,12 +4110,6 @@ <!-- Intent extra key for the event code int array while requesting ambient context consent. --> <string translatable="false" name="config_ambientContextEventArrayExtraKey"></string> - <!-- The component name for the system-wide captions service. - This service must be trusted, as it controls part of the UI of the volume bar. - Example: "com.android.captions/.SystemCaptionsService" - --> - <string name="config_defaultSystemCaptionsService" translatable="false"></string> - <!-- The component name for the system-wide captions manager service. This service must be trusted, as the system binds to it and keeps it running. Example: "com.android.captions/.SystemCaptionsManagerService" diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 94c9a122ee75..cefba56b957e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -475,6 +475,7 @@ <java-symbol type="array" name="config_network_type_tcp_buffers" /> <java-symbol type="string" name="config_tcp_buffers" /> <java-symbol type="bool" name="config_force_enable_telephony_new_data_stack" /> + <java-symbol type="bool" name="config_enable_iwlan_handover_policy" /> <java-symbol type="integer" name="config_volte_replacement_rat"/> <java-symbol type="integer" name="config_valid_wappush_index" /> <java-symbol type="integer" name="config_overrideHasPermanentMenuKey" /> @@ -3708,7 +3709,6 @@ <java-symbol type="string" name="config_defaultMusicRecognitionService" /> <java-symbol type="string" name="config_defaultAttentionService" /> <java-symbol type="string" name="config_defaultRotationResolverService" /> - <java-symbol type="string" name="config_defaultSystemCaptionsService" /> <java-symbol type="string" name="config_defaultSystemCaptionsManagerService" /> <java-symbol type="string" name="config_defaultAmbientContextDetectionService" /> <java-symbol type="string" name="config_defaultAmbientContextConsentComponent" /> diff --git a/core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java b/core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java index 0e09d563c884..e025fae4b909 100644 --- a/core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java +++ b/core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java @@ -167,7 +167,7 @@ public class VirtualAudioSessionTest { public void onPlaybackConfigChanged_sendsCallback() { List<AudioPlaybackConfiguration> configs = new ArrayList<>(); - mVirtualAudioSession.onPlaybackConfigChanged(configs); + mVirtualAudioSession.getAudioConfigChangedListener().onPlaybackConfigChanged(configs); verify(mCallback, timeout(2000)).onPlaybackConfigChanged(configs); } @@ -176,7 +176,7 @@ public class VirtualAudioSessionTest { public void onRecordingConfigChanged_sendCallback() { List<AudioRecordingConfiguration> configs = new ArrayList<>(); - mVirtualAudioSession.onRecordingConfigChanged(configs); + mVirtualAudioSession.getAudioConfigChangedListener().onRecordingConfigChanged(configs); verify(mCallback, timeout(2000)).onRecordingConfigChanged(configs); } diff --git a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java index fb0880ce3521..bbaf0862f923 100644 --- a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java +++ b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java @@ -19,7 +19,10 @@ package android.security.identity; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.os.RemoteException; import android.os.ServiceManager; +import android.security.GenerateRkpKey; +import android.security.keymaster.KeymasterDefs; class CredstoreIdentityCredentialStore extends IdentityCredentialStore { @@ -104,6 +107,16 @@ class CredstoreIdentityCredentialStore extends IdentityCredentialStore { try { IWritableCredential wc; wc = mStore.createCredential(credentialName, docType); + try { + GenerateRkpKey keyGen = new GenerateRkpKey(mContext); + // We don't know what the security level is for the backing keymint, so go ahead and + // poke the provisioner for both TEE and SB. + keyGen.notifyKeyGenerated(KeymasterDefs.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT); + keyGen.notifyKeyGenerated(KeymasterDefs.KM_SECURITY_LEVEL_STRONGBOX); + } catch (RemoteException e) { + // Not really an error state. Does not apply at all if RKP is unsupported or + // disabled on a given device. + } return new CredstoreWritableIdentityCredential(mContext, credentialName, docType, wc); } catch (android.os.RemoteException e) { throw new RuntimeException("Unexpected RemoteException ", e); diff --git a/keystore/java/android/security/KeyStoreException.java b/keystore/java/android/security/KeyStoreException.java index 54184dbf6e08..1a81dda8d56c 100644 --- a/keystore/java/android/security/KeyStoreException.java +++ b/keystore/java/android/security/KeyStoreException.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.annotation.TestApi; import android.security.keymaster.KeymasterDefs; import android.system.keystore2.ResponseCode; +import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -36,6 +37,8 @@ import java.util.Map; * is likely to succeed. */ public class KeyStoreException extends Exception { + private static final String TAG = "KeyStoreException"; + /** * This error code is for mapping errors that the caller will not know about. If the caller is * targeting an API level earlier than the one the error was introduced in, then the error will @@ -114,6 +117,27 @@ public class KeyStoreException extends Exception { * The caller should re-create the crypto object and try again. */ public static final int ERROR_KEY_OPERATION_EXPIRED = 15; + /** + * There are no keys available for attestation. + * This error is returned only on devices that rely solely on remotely-provisioned keys (see + * <a href= + * "https://android-developers.googleblog.com/2022/03/upgrading-android-attestation-remote.html" + * >Remote Key Provisioning</a>). + * + * <p>On such a device, if the caller requests key generation and includes an attestation + * challenge (indicating key attestation is required), the error will be returned in one of + * the following cases: + * <ul> + * <li>The pool of remotely-provisioned keys has been exhausted.</li> + * <li>The device is not registered with the key provisioning server.</li> + * </ul> + * </p> + * + * <p>This error is a transient one if the pool of remotely-provisioned keys has been + * exhausted. However, if the device is not registered with the server, or the key + * provisioning server refuses key issuance, this is a permanent error.</p> + */ + public static final int ERROR_ATTESTATION_KEYS_UNAVAILABLE = 16; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -132,11 +156,68 @@ public class KeyStoreException extends Exception { ERROR_UNIMPLEMENTED, ERROR_INCORRECT_USAGE, ERROR_KEY_NOT_TEMPORALLY_VALID, - ERROR_KEY_OPERATION_EXPIRED + ERROR_KEY_OPERATION_EXPIRED, + ERROR_ATTESTATION_KEYS_UNAVAILABLE }) public @interface PublicErrorCode { } + /** + * Never re-try the operation that led to this error, since it's a permanent error. + * + * This value is always returned when {@link #isTransientFailure()} is {@code false}. + */ + public static final int RETRY_NEVER = 1; + /** + * Re-try the operation that led to this error with an exponential back-off delay. + * The first delay should be between 5 to 30 seconds, and each subsequent re-try should double + * the delay time. + * + * This value is returned when {@link #isTransientFailure()} is {@code true}. + */ + public static final int RETRY_WITH_EXPONENTIAL_BACKOFF = 2; + /** + * Re-try the operation that led to this error when the device regains connectivity. + * Remote provisioning of keys requires reaching the remote server, and the device is + * currently unable to due that due to lack of network connectivity. + * + * This value is returned when {@link #isTransientFailure()} is {@code true}. + */ + public static final int RETRY_WHEN_CONNECTIVITY_AVAILABLE = 3; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = {"RETRY_"}, value = { + RETRY_NEVER, + RETRY_WITH_EXPONENTIAL_BACKOFF, + RETRY_WHEN_CONNECTIVITY_AVAILABLE, + }) + public @interface RetryPolicy { + } + + // RKP-specific error information. + /** + * Remote provisioning of attestation keys has completed successfully. + * @hide */ + public static final int RKP_SUCCESS = 0; + /** + * Remotely-provisioned keys are temporarily unavailable. This could be because of RPC + * error when talking to the remote provisioner or keys are being currently fetched and will + * be available soon. + * @hide */ + public static final int RKP_TEMPORARILY_UNAVAILABLE = 1; + /** + * Permanent failure: The RKP server has declined issuance of keys to this device. Either + * because the device is not registered with the server or the server considers the device + * not to be trustworthy. + * @hide */ + public static final int RKP_SERVER_REFUSED_ISSUANCE = 2; + /** + * The RKP server is unavailable due to lack of connectivity. The caller should re-try + * when the device has connectivity again. + * @hide */ + public static final int RKP_FETCHING_PENDING_CONNECTIVITY = 3; + // Constants for encoding information about the error encountered: // Whether the error relates to the system state/implementation as a whole, or a specific key. private static final int IS_SYSTEM_ERROR = 1 << 1; @@ -148,6 +229,21 @@ public class KeyStoreException extends Exception { // The internal error code. NOT to be returned directly to callers or made part of the // public API. private final int mErrorCode; + // The Remote Key Provisioning status. Applicable if and only if {@link #mErrorCode} is equal + // to {@link ResponseCode.OUT_OF_KEYS}. + private final int mRkpStatus; + + private static int initializeRkpStatusForRegularErrors(int errorCode) { + // Check if the system code mistakenly called a constructor of KeyStoreException with + // the OUT_OF_KEYS error code but without RKP status. + if (errorCode == ResponseCode.OUT_OF_KEYS) { + Log.e(TAG, "RKP error code without RKP status"); + // Set RKP status to RKP_SERVER_REFUSED_ISSUANCE so that the caller never retries. + return RKP_SERVER_REFUSED_ISSUANCE; + } else { + return RKP_SUCCESS; + } + } /** * @hide @@ -155,6 +251,7 @@ public class KeyStoreException extends Exception { public KeyStoreException(int errorCode, @Nullable String message) { super(message); mErrorCode = errorCode; + mRkpStatus = initializeRkpStatusForRegularErrors(errorCode); } /** @@ -165,6 +262,19 @@ public class KeyStoreException extends Exception { super(message + " (internal Keystore code: " + errorCode + " message: " + keystoreErrorMessage + ")"); mErrorCode = errorCode; + mRkpStatus = initializeRkpStatusForRegularErrors(errorCode); + } + + /** + * @hide + */ + public KeyStoreException(int errorCode, @Nullable String message, int rkpStatus) { + super(message); + mErrorCode = errorCode; + mRkpStatus = rkpStatus; + if (mErrorCode != ResponseCode.OUT_OF_KEYS) { + Log.e(TAG, "Providing RKP status for error code " + errorCode + " has no effect."); + } } /** @@ -198,6 +308,17 @@ public class KeyStoreException extends Exception { */ public boolean isTransientFailure() { PublicErrorInformation failureInfo = getErrorInformation(mErrorCode); + // Special-case handling for RKP failures: + if (mRkpStatus != RKP_SUCCESS && mErrorCode == ResponseCode.OUT_OF_KEYS) { + switch (mRkpStatus) { + case RKP_TEMPORARILY_UNAVAILABLE: + case RKP_FETCHING_PENDING_CONNECTIVITY: + return true; + case RKP_SERVER_REFUSED_ISSUANCE: + default: + return false; + } + } return (failureInfo.indicators & IS_TRANSIENT_ERROR) != 0; } @@ -225,6 +346,34 @@ public class KeyStoreException extends Exception { return (failureInfo.indicators & IS_SYSTEM_ERROR) != 0; } + /** + * Returns the re-try policy for transient failures. Valid only if + * {@link #isTransientFailure()} returns {@code True}. + */ + @RetryPolicy + public int getRetryPolicy() { + PublicErrorInformation failureInfo = getErrorInformation(mErrorCode); + // Special-case handling for RKP failures: + if (mRkpStatus != RKP_SUCCESS) { + switch (mRkpStatus) { + case RKP_TEMPORARILY_UNAVAILABLE: + return RETRY_WITH_EXPONENTIAL_BACKOFF; + case RKP_FETCHING_PENDING_CONNECTIVITY: + return RETRY_WHEN_CONNECTIVITY_AVAILABLE; + case RKP_SERVER_REFUSED_ISSUANCE: + return RETRY_NEVER; + default: + return (failureInfo.indicators & IS_TRANSIENT_ERROR) != 0 + ? RETRY_WITH_EXPONENTIAL_BACKOFF : RETRY_NEVER; + } + } + if ((failureInfo.indicators & IS_TRANSIENT_ERROR) != 0) { + return RETRY_WITH_EXPONENTIAL_BACKOFF; + } else { + return RETRY_NEVER; + } + } + @Override public String toString() { String errorCodes = String.format(" (public error code: %d internal Keystore code: %d)", @@ -469,5 +618,7 @@ public class KeyStoreException extends Exception { new PublicErrorInformation(0, ERROR_KEY_CORRUPTED)); sErrorCodeToFailureInfo.put(ResponseCode.KEY_PERMANENTLY_INVALIDATED, new PublicErrorInformation(0, ERROR_KEY_DOES_NOT_EXIST)); + sErrorCodeToFailureInfo.put(ResponseCode.OUT_OF_KEYS, + new PublicErrorInformation(IS_SYSTEM_ERROR, ERROR_ATTESTATION_KEYS_UNAVAILABLE)); } } diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java index e7961c94928c..5950b5bc7231 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -28,7 +28,6 @@ import android.hardware.security.keymint.Tag; import android.os.Build; import android.os.RemoteException; import android.security.GenerateRkpKey; -import android.security.GenerateRkpKeyException; import android.security.KeyPairGeneratorSpec; import android.security.KeyStore2; import android.security.KeyStoreException; @@ -618,18 +617,44 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato @Override public KeyPair generateKeyPair() { - try { - return generateKeyPairHelper(); - } catch (GenerateRkpKeyException e) { - try { - return generateKeyPairHelper(); - } catch (GenerateRkpKeyException f) { - throw new ProviderException("Failed to provision new attestation keys."); + GenerateKeyPairHelperResult result = new GenerateKeyPairHelperResult(0, null); + for (int i = 0; i < 2; i++) { + /** + * NOTE: There is no need to delay between re-tries because the call to + * GenerateRkpKey.notifyEmpty() will delay for a while before returning. + */ + result = generateKeyPairHelper(); + if (result.rkpStatus == KeyStoreException.RKP_SUCCESS) { + return result.keyPair; } } + + // RKP failure + if (result.rkpStatus != KeyStoreException.RKP_SUCCESS) { + KeyStoreException ksException = new KeyStoreException(ResponseCode.OUT_OF_KEYS, + "Could not get RKP keys", result.rkpStatus); + throw new ProviderException("Failed to provision new attestation keys.", ksException); + } + + return result.keyPair; + } + + private static class GenerateKeyPairHelperResult { + // Zero indicates success, non-zero indicates failure. Values should be + // {@link android.security.KeyStoreException#RKP_TEMPORARILY_UNAVAILABLE}, + // {@link android.security.KeyStoreException#RKP_SERVER_REFUSED_ISSUANCE}, + // {@link android.security.KeyStoreException#RKP_FETCHING_PENDING_CONNECTIVITY} + public final int rkpStatus; + @Nullable + public final KeyPair keyPair; + + private GenerateKeyPairHelperResult(int rkpStatus, KeyPair keyPair) { + this.rkpStatus = rkpStatus; + this.keyPair = keyPair; + } } - private KeyPair generateKeyPairHelper() throws GenerateRkpKeyException { + private GenerateKeyPairHelperResult generateKeyPairHelper() { if (mKeyStore == null || mSpec == null) { throw new IllegalStateException("Not initialized"); } @@ -679,7 +704,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato Log.d(TAG, "Couldn't connect to the RemoteProvisioner backend.", e); } success = true; - return new KeyPair(publicKey, publicKey.getPrivateKey()); + KeyPair kp = new KeyPair(publicKey, publicKey.getPrivateKey()); + return new GenerateKeyPairHelperResult(0, kp); } catch (android.security.KeyStoreException e) { switch (e.getErrorCode()) { case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE: @@ -688,11 +714,19 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato GenerateRkpKey keyGen = new GenerateRkpKey(ActivityThread .currentApplication()); try { + //TODO: When detailed error information is available from the remote + //provisioner, propagate it up. keyGen.notifyEmpty(securityLevel); } catch (RemoteException f) { - throw new ProviderException("Failed to talk to RemoteProvisioner", f); + KeyStoreException ksException = new KeyStoreException( + ResponseCode.OUT_OF_KEYS, + "Remote exception: " + f.getMessage(), + KeyStoreException.RKP_TEMPORARILY_UNAVAILABLE); + throw new ProviderException("Failed to talk to RemoteProvisioner", + ksException); } - throw new GenerateRkpKeyException(); + return new GenerateKeyPairHelperResult( + KeyStoreException.RKP_TEMPORARILY_UNAVAILABLE, null); default: ProviderException p = new ProviderException("Failed to generate key pair.", e); if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) { diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 59d03c738723..a2f9e884b37d 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -74,6 +74,10 @@ <!-- PIP stash offset size, which is the width of visible PIP region when stashed. --> <dimen name="pip_stash_offset">32dp</dimen> + <!-- PIP shadow radius, originally as + WindowConfiguration#PINNED_WINDOWING_MODE_ELEVATION_IN_DIP --> + <dimen name="pip_shadow_radius">5dp</dimen> + <dimen name="dismiss_target_x_size">24dp</dimen> <dimen name="floating_dismiss_bottom_margin">50dp</dimen> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java index 7cf359729ee8..e71a59d26740 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java @@ -16,6 +16,7 @@ package com.android.wm.shell.back; +import android.view.KeyEvent; import android.view.MotionEvent; import android.window.BackEvent; @@ -29,8 +30,14 @@ public interface BackAnimation { /** * Called when a {@link MotionEvent} is generated by a back gesture. + * + * @param event the original {@link MotionEvent} + * @param action the original {@link KeyEvent#getAction()} when the event was dispatched to + * the process. This is forwarded separately because the input pipeline may mutate + * the {#event} action state later. + * @param swipeEdge the edge from which the swipe begins. */ - void onBackMotion(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge); + void onBackMotion(MotionEvent event, int action, @BackEvent.SwipeEdge int swipeEdge); /** * Sets whether the back gesture is past the trigger threshold or not. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java index 08cb252cdf43..93ee3f5378e8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java @@ -138,8 +138,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } @Override - public void onBackMotion(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge) { - mShellExecutor.execute(() -> onMotionEvent(event, swipeEdge)); + public void onBackMotion( + MotionEvent event, int action, @BackEvent.SwipeEdge int swipeEdge) { + mShellExecutor.execute(() -> onMotionEvent(event, action, swipeEdge)); } @Override @@ -209,13 +210,13 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont * Called when a new motion event needs to be transferred to this * {@link BackAnimationController} */ - public void onMotionEvent(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge) { - int action = event.getActionMasked(); + public void onMotionEvent(MotionEvent event, int action, @BackEvent.SwipeEdge int swipeEdge) { if (action == MotionEvent.ACTION_DOWN) { initAnimation(event); } else if (action == MotionEvent.ACTION_MOVE) { onMove(event, swipeEdge); } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Finishing gesture with event: %s", event); onGestureFinished(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl index ef627647794e..062e3ba26356 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl @@ -26,12 +26,13 @@ oneway interface IPipAnimationListener { void onPipAnimationStarted(); /** - * Notifies the listener about PiP round corner radius changes. + * Notifies the listener about PiP resource dimensions changed. * Listener can expect an immediate callback the first time they attach. * * @param cornerRadius the pixel value of the corner radius, zero means it's disabled. + * @param shadowRadius the pixel value of the shadow radius, zero means it's disabled. */ - void onPipCornerRadiusChanged(int cornerRadius); + void onPipResourceDimensionsChanged(int cornerRadius, int shadowRadius); /** * Notifies the listener that user leaves PiP by tapping on the expand button. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java index 77fd228af286..30601d732593 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java @@ -489,7 +489,8 @@ public class PipAnimationController { final float alpha = getStartValue() * (1 - fraction) + getEndValue() * fraction; setCurrentValue(alpha); getSurfaceTransactionHelper().alpha(tx, leash, alpha) - .round(tx, leash, shouldApplyCornerRadius()); + .round(tx, leash, shouldApplyCornerRadius()) + .shadow(tx, leash); tx.apply(); } @@ -502,7 +503,8 @@ public class PipAnimationController { getSurfaceTransactionHelper() .resetScale(tx, leash, getDestinationBounds()) .crop(tx, leash, getDestinationBounds()) - .round(tx, leash, shouldApplyCornerRadius()); + .round(tx, leash, shouldApplyCornerRadius()) + .shadow(tx, leash); tx.show(leash); tx.apply(); } @@ -589,7 +591,8 @@ public class PipAnimationController { } else { getSurfaceTransactionHelper().crop(tx, leash, base) .scale(tx, leash, base, bounds, angle) - .round(tx, leash, base, bounds); + .round(tx, leash, base, bounds) + .shadow(tx, leash); } } else { final Rect insets = computeInsets(fraction); @@ -598,8 +601,9 @@ public class PipAnimationController { if (shouldApplyCornerRadius()) { final Rect sourceBounds = new Rect(initialContainerRect); sourceBounds.inset(insets); - getSurfaceTransactionHelper().round(tx, leash, - sourceBounds, bounds); + getSurfaceTransactionHelper() + .round(tx, leash, sourceBounds, bounds) + .shadow(tx, leash); } } if (!handlePipTransaction(leash, tx, bounds)) { @@ -650,7 +654,9 @@ public class PipAnimationController { insets, degree, x, y, isOutPipDirection, rotationDelta == ROTATION_270 /* clockwise */); if (shouldApplyCornerRadius()) { - getSurfaceTransactionHelper().round(tx, leash, sourceBounds, bounds); + getSurfaceTransactionHelper() + .round(tx, leash, sourceBounds, bounds) + .shadow(tx, leash); } tx.apply(); } @@ -668,7 +674,8 @@ public class PipAnimationController { void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) { getSurfaceTransactionHelper() .alpha(tx, leash, 1f) - .round(tx, leash, shouldApplyCornerRadius()); + .round(tx, leash, shouldApplyCornerRadius()) + .shadow(tx, leash); // TODO(b/178632364): this is a work around for the black background when // entering PiP in buttion navigation mode. if (isInPipDirection(direction)) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java index d7322ce7beda..24ad2c18aaa4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java @@ -37,6 +37,7 @@ public class PipSurfaceTransactionHelper { private final Rect mTmpDestinationRect = new Rect(); private int mCornerRadius; + private int mShadowRadius; /** * Called when display size or font size of settings changed @@ -45,6 +46,7 @@ public class PipSurfaceTransactionHelper { */ public void onDensityOrFontScaleChanged(Context context) { mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius); + mShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius); } /** @@ -200,14 +202,11 @@ public class PipSurfaceTransactionHelper { } /** - * Re-parents the snapshot to the parent's surface control and shows it. + * Operates the shadow radius on a given transaction and leash + * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ - public PipSurfaceTransactionHelper reparentAndShowSurfaceSnapshot( - SurfaceControl.Transaction t, SurfaceControl parent, SurfaceControl snapshot) { - t.reparent(snapshot, parent); - t.setLayer(snapshot, Integer.MAX_VALUE); - t.show(snapshot); - t.apply(); + public PipSurfaceTransactionHelper shadow(SurfaceControl.Transaction tx, SurfaceControl leash) { + tx.setShadowRadius(leash, mShadowRadius); return this; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index ad5d85cc083a..623ef05ec7e2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -131,12 +131,13 @@ public class PipController implements PipTransitionController.PipTransitionCallb void onPipAnimationStarted(); /** - * Notifies the listener about PiP round corner radius changes. + * Notifies the listener about PiP resource dimensions changed. * Listener can expect an immediate callback the first time they attach. * * @param cornerRadius the pixel value of the corner radius, zero means it's disabled. + * @param shadowRadius the pixel value of the shadow radius, zero means it's disabled. */ - void onPipCornerRadiusChanged(int cornerRadius); + void onPipResourceDimensionsChanged(int cornerRadius, int shadowRadius); /** * Notifies the listener that user leaves PiP by tapping on the expand button. @@ -479,7 +480,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb private void onDensityOrFontScaleChanged() { mPipTaskOrganizer.onDensityOrFontScaleChanged(mContext); - onPipCornerRadiusChanged(); + onPipResourceDimensionsChanged(); } private void onOverlayChanged() { @@ -590,14 +591,14 @@ public class PipController implements PipTransitionController.PipTransitionCallb private void setPinnedStackAnimationListener(PipAnimationListener callback) { mPinnedStackAnimationRecentsCallback = callback; - onPipCornerRadiusChanged(); + onPipResourceDimensionsChanged(); } - private void onPipCornerRadiusChanged() { + private void onPipResourceDimensionsChanged() { if (mPinnedStackAnimationRecentsCallback != null) { - final int cornerRadius = - mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius); - mPinnedStackAnimationRecentsCallback.onPipCornerRadiusChanged(cornerRadius); + mPinnedStackAnimationRecentsCallback.onPipResourceDimensionsChanged( + mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius), + mContext.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius)); } } @@ -916,8 +917,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb } @Override - public void onPipCornerRadiusChanged(int cornerRadius) { - mListener.call(l -> l.onPipCornerRadiusChanged(cornerRadius)); + public void onPipResourceDimensionsChanged(int cornerRadius, int shadowRadius) { + mListener.call(l -> l.onPipResourceDimensionsChanged(cornerRadius, shadowRadius)); } @Override diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt index f6abc75037ed..b137e92881a5 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt @@ -28,9 +28,6 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import org.junit.Assume -import org.junit.Before import org.junit.runner.RunWith import org.junit.Test import org.junit.runners.Parameterized @@ -52,11 +49,6 @@ open class DismissBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScree private val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager private val displaySize = DisplayMetrics() - @Before - open fun before() { - Assume.assumeFalse(isShellTransitionsEnabled) - } - override val transition: FlickerBuilder.() -> Unit get() = buildTransition { setup { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreenShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreenShellTransit.kt deleted file mode 100644 index dd744b3c45ab..000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreenShellTransit.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.flicker.bubble - -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice - -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.annotation.Group4 -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import org.junit.Assume -import org.junit.Before - -import org.junit.runner.RunWith -import org.junit.runners.Parameterized - -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@Group4 -@FlakyTest(bugId = 217777115) -class DismissBubbleScreenShellTransit( - testSpec: FlickerTestParameter -) : DismissBubbleScreen(testSpec) { - @Before - override fun before() { - Assume.assumeTrue(isShellTransitionsEnabled) - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt index 2ec743c10413..f288b0a24d9d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt @@ -24,9 +24,6 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import org.junit.Assume -import org.junit.Before import org.junit.runner.RunWith import org.junit.Test import org.junit.runners.Parameterized @@ -47,11 +44,6 @@ import org.junit.runners.Parameterized @Group4 open class ExpandBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) { - @Before - open fun before() { - Assume.assumeFalse(isShellTransitionsEnabled) - } - override val transition: FlickerBuilder.() -> Unit get() = buildTransition { setup { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreenShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreenShellTransit.kt deleted file mode 100644 index d92ec7781005..000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreenShellTransit.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.flicker.bubble - -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.annotation.Group4 -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import org.junit.Assume -import org.junit.Before -import org.junit.runner.RunWith -import org.junit.runners.Parameterized - -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@Group4 -@FlakyTest(bugId = 217777115) -class ExpandBubbleScreenShellTransit( - testSpec: FlickerTestParameter -) : ExpandBubbleScreen(testSpec) { - @Before - override fun before() { - Assume.assumeTrue(isShellTransitionsEnabled) - } -}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt index c43230e77683..0bb4d398bff4 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt @@ -17,15 +17,11 @@ package com.android.wm.shell.flicker.bubble import android.platform.test.annotations.Presubmit -import androidx.test.filters.FlakyTest import android.platform.test.annotations.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import org.junit.Assume -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @@ -45,11 +41,6 @@ import org.junit.runners.Parameterized @Group4 open class LaunchBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) { - @Before - open fun before() { - Assume.assumeFalse(isShellTransitionsEnabled) - } - override val transition: FlickerBuilder.() -> Unit get() = buildTransition { transitions { @@ -61,16 +52,6 @@ open class LaunchBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen @Presubmit @Test open fun testAppIsAlwaysVisible() { - Assume.assumeFalse(isShellTransitionsEnabled) - testSpec.assertLayers { - this.isVisible(testApp.component) - } - } - - @FlakyTest(bugId = 218642026) - @Test - open fun testAppIsAlwaysVisible_ShellTransit() { - Assume.assumeTrue(isShellTransitionsEnabled) testSpec.assertLayers { this.isVisible(testApp.component) } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreenShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreenShellTransit.kt deleted file mode 100644 index 9350868a99f4..000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreenShellTransit.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.flicker.bubble - -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.annotation.Group4 -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import org.junit.Assume -import org.junit.Before -import org.junit.runner.RunWith -import org.junit.runners.Parameterized - -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@Group4 -@FlakyTest(bugId = 217777115) -class LaunchBubbleScreenShellTransit( - testSpec: FlickerTestParameter -) : LaunchBubbleScreen(testSpec) { - @Before - override fun before() { - Assume.assumeTrue(isShellTransitionsEnabled) - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt index e2d08346efb6..a3ed79bf0409 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt @@ -74,7 +74,7 @@ class ExitPipViaExpandButtonClickTest( // This will bring PipApp to fullscreen pipApp.expandPipWindowToApp(wmHelper) // Wait until the other app is no longer visible - wmHelper.waitForSurfaceAppeared(testApp.component) + wmHelper.waitForWindowSurfaceDisappeared(testApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt index 87e927fd50ea..8729bb6776f0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt @@ -24,10 +24,7 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.traces.region.RegionSubject -import org.junit.Assume -import org.junit.Before import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -61,11 +58,6 @@ import org.junit.runners.Parameterized open class MovePipDownShelfHeightChangeTest( testSpec: FlickerTestParameter ) : MovePipShelfHeightTransition(testSpec) { - @Before - open fun before() { - Assume.assumeFalse(isShellTransitionsEnabled) - } - /** * Defines the transition used to run the test */ diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest_ShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest_ShellTransit.kt deleted file mode 100644 index 0ff260b94dc8..000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest_ShellTransit.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.flicker.pip - -import androidx.test.filters.FlakyTest -import android.platform.test.annotations.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.annotation.Group3 -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import org.junit.Assume -import org.junit.Before -import org.junit.FixMethodOrder -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test Pip movement with Launcher shelf height change (decrease). - * - * To run this test: `atest WMShellFlickerTests:MovePipDownShelfHeightChangeTest` - * - * Actions: - * Launch [pipApp] in pip mode - * Launch [testApp] - * Press home - * Check if pip window moves down (visually) - * - * Notes: - * 1. Some default assertions (e.g., nav bar, status bar and screen covered) - * are inherited [PipTransition] - * 2. Part of the test setup occurs automatically via - * [com.android.server.wm.flicker.TransitionRunnerWithRules], - * including configuring navigation mode, initial orientation and ensuring no - * apps are running before setup - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group3 -@FlakyTest(bugId = 219693385) -class MovePipDownShelfHeightChangeTest_ShellTransit( - testSpec: FlickerTestParameter -) : MovePipDownShelfHeightChangeTest(testSpec) { - @Before - override fun before() { - Assume.assumeTrue(isShellTransitionsEnabled) - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt index c8ced1c9df12..6af01e24f58c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt @@ -64,7 +64,6 @@ import org.junit.runners.Parameterized @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @Group4 -@FlakyTest(bugId = 218604389) open class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { private val fixedApp = FixedAppHelper(instrumentation) private val screenBoundsStart = WindowUtils.getDisplayBounds(testSpec.startRotation) @@ -138,7 +137,7 @@ open class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testS */ @Presubmit @Test - fun pipLayerRotates_StartingBounds() { + open fun pipLayerRotates_StartingBounds() { testSpec.assertLayersStart { visibleRegion(pipApp.component).coversAtMost(screenBoundsStart) } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTestShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTestShellTransit.kt index a017f56af5bd..2252a949ba00 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTestShellTransit.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTestShellTransit.kt @@ -34,10 +34,12 @@ import org.junit.runners.Parameterized @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @Group4 -@FlakyTest(bugId = 217777115) class PipRotationTestShellTransit(testSpec: FlickerTestParameter) : PipRotationTest(testSpec) { @Before override fun before() { Assume.assumeTrue(isShellTransitionsEnabled) } + + @FlakyTest(bugId = 227214914) + override fun pipLayerRotates_StartingBounds() = super.pipLayerRotates_StartingBounds() } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt index f7384e742a04..81403d08ff20 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt @@ -28,13 +28,10 @@ import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.helpers.WindowUtils -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE import com.android.wm.shell.flicker.testapp.Components import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION -import org.junit.Assume -import org.junit.Before import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -57,11 +54,6 @@ open class SetRequestedOrientationWhilePinnedTest( private val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0) private val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90) - @Before - open fun before() { - Assume.assumeFalse(isShellTransitionsEnabled) - } - override val transition: FlickerBuilder.() -> Unit get() = { setup { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt deleted file mode 100644 index 8d764a8d0e69..000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.flicker.pip - -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.annotation.Group4 -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import org.junit.Assume -import org.junit.Before -import org.junit.FixMethodOrder -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test exiting Pip with orientation changes. - * To run this test: `atest WMShellFlickerTests:SetRequestedOrientationWhilePinnedTestShellTransit` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group4 -@FlakyTest(bugId = 217777115) -class SetRequestedOrientationWhilePinnedTestShellTransit( - testSpec: FlickerTestParameter -) : SetRequestedOrientationWhilePinnedTest(testSpec) { - @Before - override fun before() { - Assume.assumeTrue(isShellTransitionsEnabled) - } -} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java index 05230a9417bb..7c1fae3a849b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java @@ -118,6 +118,7 @@ public class BackAnimationControllerTest { BackNavigationInfo.TYPE_CROSS_ACTIVITY); mController.onMotionEvent( MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0), + MotionEvent.ACTION_DOWN, BackEvent.EDGE_LEFT); verify(mTransaction).setBuffer(screenshotSurface, hardwareBuffer); verify(mTransaction).setVisibility(screenshotSurface, true); @@ -133,9 +134,11 @@ public class BackAnimationControllerTest { BackNavigationInfo.TYPE_CROSS_ACTIVITY); mController.onMotionEvent( MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0), + MotionEvent.ACTION_DOWN, BackEvent.EDGE_LEFT); mController.onMotionEvent( MotionEvent.obtain(10, 0, MotionEvent.ACTION_MOVE, 100, 100, 0), + MotionEvent.ACTION_MOVE, BackEvent.EDGE_LEFT); verify(mTransaction).setPosition(animationTarget.leash, 100, 100); verify(mTransaction, atLeastOnce()).apply(); @@ -151,12 +154,14 @@ public class BackAnimationControllerTest { // Check that back start is dispatched. mController.onMotionEvent( MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0), + MotionEvent.ACTION_DOWN, BackEvent.EDGE_LEFT); verify(mIOnBackInvokedCallback).onBackStarted(); // Check that back progress is dispatched. mController.onMotionEvent( MotionEvent.obtain(10, 0, MotionEvent.ACTION_MOVE, 100, 100, 0), + MotionEvent.ACTION_MOVE, BackEvent.EDGE_LEFT); ArgumentCaptor<BackEvent> backEventCaptor = ArgumentCaptor.forClass(BackEvent.class); verify(mIOnBackInvokedCallback).onBackProgressed(backEventCaptor.capture()); @@ -166,6 +171,7 @@ public class BackAnimationControllerTest { mController.setTriggerBack(true); // Fake trigger back mController.onMotionEvent( MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0), + MotionEvent.ACTION_UP, BackEvent.EDGE_LEFT); verify(mIOnBackInvokedCallback).onBackInvoked(); } diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 0e4a1f945b85..99fd463b0660 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -74,7 +74,15 @@ bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, con if (backBuffer.get() == nullptr) { return false; } - LightingInfo::updateLighting(lightGeometry, lightInfo); + + // update the coordinates of the global light position based on surface rotation + SkPoint lightCenter = mVkSurface->getCurrentPreTransform().mapXY(lightGeometry.center.x, + lightGeometry.center.y); + LightGeometry localGeometry = lightGeometry; + localGeometry.center.x = lightCenter.fX; + localGeometry.center.y = lightCenter.fY; + + LightingInfo::updateLighting(localGeometry, lightInfo); renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer, mVkSurface->getCurrentPreTransform()); diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index 00c4a9782f33..a2826cb58ccf 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -85,12 +85,13 @@ bool checkLoop(int32_t *loop) } // namespace SoundPool::SoundPool( - int32_t maxStreams, const audio_attributes_t* attributes, const std::string& opPackageName) + int32_t maxStreams, const audio_attributes_t& attributes, + const std::string& opPackageName) : mStreamManager(maxStreams, kStreamManagerThreads, attributes, opPackageName) { ALOGV("%s(maxStreams=%d, attr={ content_type=%d, usage=%d, flags=0x%x, tags=%s })", __func__, maxStreams, - attributes->content_type, attributes->usage, attributes->flags, attributes->tags); + attributes.content_type, attributes.usage, attributes.flags, attributes.tags); } SoundPool::~SoundPool() diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h index ffb1c997393a..6bb971b07e43 100644 --- a/media/jni/soundpool/SoundPool.h +++ b/media/jni/soundpool/SoundPool.h @@ -31,7 +31,7 @@ namespace android { */ class SoundPool { public: - SoundPool(int32_t maxStreams, const audio_attributes_t* attributes, + SoundPool(int32_t maxStreams, const audio_attributes_t& attributes, const std::string& opPackageName = {}); ~SoundPool(); diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp index 7f987e31d1d8..487a696d8765 100644 --- a/media/jni/soundpool/StreamManager.cpp +++ b/media/jni/soundpool/StreamManager.cpp @@ -106,10 +106,10 @@ int32_t StreamMap::getNextIdForStream(Stream* stream) const { #pragma clang diagnostic ignored "-Wthread-safety-analysis" StreamManager::StreamManager( - int32_t streams, size_t threads, const audio_attributes_t* attributes, + int32_t streams, size_t threads, const audio_attributes_t& attributes, std::string opPackageName) : StreamMap(streams) - , mAttributes(*attributes) + , mAttributes(attributes) , mOpPackageName(std::move(opPackageName)) , mLockStreamManagerStop(streams == 1 || kForceLockStreamManagerStop) { diff --git a/media/jni/soundpool/StreamManager.h b/media/jni/soundpool/StreamManager.h index 85b468cd2cbc..ec65b0c49dc4 100644 --- a/media/jni/soundpool/StreamManager.h +++ b/media/jni/soundpool/StreamManager.h @@ -387,7 +387,7 @@ class StreamManager : public StreamMap { public: // Note: the SoundPool pointer is only used for stream initialization. // It is not stored in StreamManager. - StreamManager(int32_t streams, size_t threads, const audio_attributes_t* attributes, + StreamManager(int32_t streams, size_t threads, const audio_attributes_t& attributes, std::string opPackageName); ~StreamManager(); diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp index 14b0c11c986a..5264772be7c3 100644 --- a/media/jni/soundpool/android_media_SoundPool.cpp +++ b/media/jni/soundpool/android_media_SoundPool.cpp @@ -520,7 +520,7 @@ android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz, (audio_flags_mask_t) env->GetIntField(jaa, javaAudioAttrFields.fieldFlags); ScopedUtfChars opPackageNameStr(env, opPackageName); auto soundPool = std::make_shared<SoundPool>( - maxChannels, &audioAttributes, opPackageNameStr.c_str()); + maxChannels, audioAttributes, opPackageNameStr.c_str()); soundPool->setCallback(android_media_callback, nullptr /* user */); // register with SoundPoolManager. diff --git a/media/jni/soundpool/tests/soundpool_stress.cpp b/media/jni/soundpool/tests/soundpool_stress.cpp index 7d9b6a21b5c4..0116a99b2ba9 100644 --- a/media/jni/soundpool/tests/soundpool_stress.cpp +++ b/media/jni/soundpool/tests/soundpool_stress.cpp @@ -274,7 +274,7 @@ int main(int argc, char *argv[]) .content_type = AUDIO_CONTENT_TYPE_MUSIC, .usage = AUDIO_USAGE_MEDIA, }; - auto soundPool = std::make_unique<SoundPool>(maxStreams, &aa); + auto soundPool = std::make_unique<SoundPool>(maxStreams, aa); gCallbackManager.setSoundPool(soundPool.get()); soundPool->setCallback(StaticCallbackManager, &gCallbackManager); diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java index 2af7e00f9128..38d851eb76aa 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java @@ -41,6 +41,10 @@ import java.util.Arrays; import java.util.Enumeration; import java.util.List; import java.util.Locale; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -51,8 +55,8 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { private static final String TAG = "InstallationAsyncTask"; private static final int MIN_SHARED_MEMORY_SIZE = 8 << 10; // 8KiB - private static final int MAX_SHARED_MEMORY_SIZE = 1024 << 10; // 1MiB - private static final int DEFAULT_SHARED_MEMORY_SIZE = 64 << 10; // 64KiB + private static final int MAX_SHARED_MEMORY_SIZE = 8 << 20; // 8MiB + private static final int DEFAULT_SHARED_MEMORY_SIZE = 512 << 10; // 512KiB private static final String SHARED_MEMORY_SIZE_PROP = "dynamic_system.data_transfer.shared_memory.size"; @@ -488,7 +492,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { installWritablePartition("userdata", mUserdataSize); } - private void installImages() throws IOException, ImageValidationException { + private void installImages() throws ExecutionException, IOException, ImageValidationException { if (mStream != null) { if (mIsZip) { installStreamingZipUpdate(); @@ -500,7 +504,8 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { } } - private void installStreamingGzUpdate() throws IOException, ImageValidationException { + private void installStreamingGzUpdate() + throws ExecutionException, IOException, ImageValidationException { Log.d(TAG, "To install a streaming GZ update"); installImage("system", mSystemSize, new GZIPInputStream(mStream)); } @@ -528,7 +533,8 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { return total; } - private void installStreamingZipUpdate() throws IOException, ImageValidationException { + private void installStreamingZipUpdate() + throws ExecutionException, IOException, ImageValidationException { Log.d(TAG, "To install a streaming ZIP update"); ZipInputStream zis = new ZipInputStream(mStream); @@ -548,7 +554,8 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { } } - private void installLocalZipUpdate() throws IOException, ImageValidationException { + private void installLocalZipUpdate() + throws ExecutionException, IOException, ImageValidationException { Log.d(TAG, "To install a local ZIP update"); Enumeration<? extends ZipEntry> entries = mZipFile.entries(); @@ -569,7 +576,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { } private void installImageFromAnEntry(ZipEntry entry, InputStream is) - throws IOException, ImageValidationException { + throws ExecutionException, IOException, ImageValidationException { String name = entry.getName(); Log.d(TAG, "ZipEntry: " + name); @@ -581,7 +588,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { } private void installImage(String partitionName, long uncompressedSize, InputStream is) - throws IOException, ImageValidationException { + throws ExecutionException, IOException, ImageValidationException { SparseInputStream sis = new SparseInputStream(new BufferedInputStream(is)); @@ -637,27 +644,51 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { long prevInstalledSize = 0; long installedSize = 0; byte[] bytes = new byte[memoryFile.length()]; - int numBytesRead; + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future<Boolean> submitPromise = null; + + while (true) { + final int numBytesRead = sis.read(bytes, 0, bytes.length); + + if (submitPromise != null) { + // Wait until the previous submit task is complete. + while (true) { + try { + if (!submitPromise.get()) { + throw new IOException("Failed submitFromAshmem() to DynamicSystem"); + } + break; + } catch (InterruptedException e) { + // Ignore. + } + } + + // Publish the progress of the previous submit task. + if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) { + publishProgress(installedSize); + prevInstalledSize = installedSize; + } + } + + // Ensure the previous submit task (submitPromise) is complete before exiting the loop. + if (numBytesRead < 0) { + break; + } - while ((numBytesRead = sis.read(bytes, 0, bytes.length)) != -1) { if (isCancelled()) { return; } memoryFile.writeBytes(bytes, 0, 0, numBytesRead); + submitPromise = + executor.submit(() -> mInstallationSession.submitFromAshmem(numBytesRead)); - if (!mInstallationSession.submitFromAshmem(numBytesRead)) { - throw new IOException("Failed write() to DynamicSystem"); - } - + // Even though we update the bytes counter here, the actual progress is updated only + // after the submit task (submitPromise) is complete. installedSize += numBytesRead; - - if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) { - publishProgress(installedSize); - prevInstalledSize = installedSize; - } } + // Ensure a 100% mark is published. if (prevInstalledSize != partitionSize) { publishProgress(partitionSize); } diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index a9f5f8582403..804b8f187405 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1434,6 +1434,8 @@ <string name="guest_remove_guest_dialog_title">Remove guest?</string> <!-- Label for button in confirmation dialog when resetting guest user [CHAR LIMIT=35] --> <string name="guest_reset_guest_confirm_button">Reset</string> + <!-- Label for button in confirmation dialog when removing guest session [CHAR LIMIT=35] --> + <string name="guest_remove_guest_confirm_button">Remove</string> <!-- Status message indicating the device is in the process of resetting the guest user. [CHAR_LIMIT=NONE] --> <string name="guest_resetting">Resetting guest\u2026</string> <!-- An option in a photo selection dialog to take a new photo [CHAR LIMIT=50] --> diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 1fc2b8563dc1..a10ca9e75355 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -495,6 +495,9 @@ <!-- Permission needed for CTS test - DefaultDisplayModeTest --> <uses-permission android:name="android.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE" /> + <!-- Permissions needed for manual testing telephony time zone detector behavior --> + <uses-permission android:name="android.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE" /> + <!-- Permissions needed for CTS test - TimeManagerTest --> <uses-permission android:name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" /> <uses-permission android:name="android.permission.SUGGEST_EXTERNAL_TIME" /> @@ -671,6 +674,9 @@ <!-- Permission required for CTS test - CtsTelephonyTestCases --> <uses-permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE" /> + <!-- Permission required for CTS test - CtsPersistentDataBlockManagerTestCases --> + <uses-permission android:name="android.permission.ACCESS_PDB_STATE" /> + <!-- Permission required for CTS test - CtsAppEnumerationTestCases --> <uses-permission android:name="android.permission.MAKE_UID_VISIBLE" /> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 8df614d3c522..9767f04ac9d4 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -873,9 +873,6 @@ <!-- Message of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] --> <string name="guest_exit_guest_dialog_message">All apps and data in this session will be deleted.</string> - <!-- Label for button in confirmation dialog when exiting guest session [CHAR LIMIT=35] --> - <string name="guest_exit_guest_dialog_remove">Remove</string> - <!-- Title of the notification when resuming an existing guest session [CHAR LIMIT=NONE] --> <string name="guest_wipe_session_title">Welcome back, guest!</string> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java index 567e7aa3d78f..034d1ff1b049 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java @@ -30,14 +30,16 @@ import android.window.PictureInPictureSurfaceTransaction; */ public class PipSurfaceTransactionHelper { private final int mCornerRadius; + private final int mShadowRadius; private final Matrix mTmpTransform = new Matrix(); private final float[] mTmpFloat9 = new float[9]; private final RectF mTmpSourceRectF = new RectF(); private final RectF mTmpDestinationRectF = new RectF(); private final Rect mTmpDestinationRect = new Rect(); - public PipSurfaceTransactionHelper(int cornerRadius) { + public PipSurfaceTransactionHelper(int cornerRadius, int shadowRadius) { mCornerRadius = cornerRadius; + mShadowRadius = shadowRadius; } public PictureInPictureSurfaceTransaction scale( @@ -52,9 +54,10 @@ public class PipSurfaceTransactionHelper { final float cornerRadius = getScaledCornerRadius(sourceBounds, destinationBounds); tx.setMatrix(leash, mTmpTransform, mTmpFloat9) .setPosition(leash, positionX, positionY) - .setCornerRadius(leash, cornerRadius); + .setCornerRadius(leash, cornerRadius) + .setShadowRadius(leash, mShadowRadius); return newPipSurfaceTransaction(positionX, positionY, - mTmpFloat9, 0 /* rotation */, cornerRadius, sourceBounds); + mTmpFloat9, 0 /* rotation */, cornerRadius, mShadowRadius, sourceBounds); } public PictureInPictureSurfaceTransaction scale( @@ -69,9 +72,10 @@ public class PipSurfaceTransactionHelper { final float cornerRadius = getScaledCornerRadius(sourceBounds, destinationBounds); tx.setMatrix(leash, mTmpTransform, mTmpFloat9) .setPosition(leash, positionX, positionY) - .setCornerRadius(leash, cornerRadius); + .setCornerRadius(leash, cornerRadius) + .setShadowRadius(leash, mShadowRadius); return newPipSurfaceTransaction(positionX, positionY, - mTmpFloat9, degree, cornerRadius, sourceBounds); + mTmpFloat9, degree, cornerRadius, mShadowRadius, sourceBounds); } public PictureInPictureSurfaceTransaction scaleAndCrop( @@ -92,9 +96,10 @@ public class PipSurfaceTransactionHelper { tx.setMatrix(leash, mTmpTransform, mTmpFloat9) .setWindowCrop(leash, mTmpDestinationRect) .setPosition(leash, left, top) - .setCornerRadius(leash, cornerRadius); + .setCornerRadius(leash, cornerRadius) + .setShadowRadius(leash, mShadowRadius); return newPipSurfaceTransaction(left, top, - mTmpFloat9, 0 /* rotation */, cornerRadius, mTmpDestinationRect); + mTmpFloat9, 0 /* rotation */, cornerRadius, mShadowRadius, mTmpDestinationRect); } public PictureInPictureSurfaceTransaction scaleAndRotate( @@ -124,9 +129,10 @@ public class PipSurfaceTransactionHelper { tx.setMatrix(leash, mTmpTransform, mTmpFloat9) .setWindowCrop(leash, mTmpDestinationRect) .setPosition(leash, adjustedPositionX, adjustedPositionY) - .setCornerRadius(leash, cornerRadius); + .setCornerRadius(leash, cornerRadius) + .setShadowRadius(leash, mShadowRadius); return newPipSurfaceTransaction(adjustedPositionX, adjustedPositionY, - mTmpFloat9, degree, cornerRadius, mTmpDestinationRect); + mTmpFloat9, degree, cornerRadius, mShadowRadius, mTmpDestinationRect); } /** @return the round corner radius scaled by given from and to bounds */ @@ -137,12 +143,13 @@ public class PipSurfaceTransactionHelper { } private static PictureInPictureSurfaceTransaction newPipSurfaceTransaction( - float posX, float posY, float[] float9, float rotation, float cornerRadius, - Rect windowCrop) { + float posX, float posY, float[] float9, float rotation, + float cornerRadius, float shadowRadius, Rect windowCrop) { return new PictureInPictureSurfaceTransaction.Builder() .setPosition(posX, posY) .setTransform(float9, rotation) .setCornerRadius(cornerRadius) + .setShadowRadius(shadowRadius) .setWindowCrop(windowCrop) .build(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index fcabbbca6e34..3b8a29bfe8c4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -3562,8 +3562,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab pw.println(" udfpsEnrolled=" + isUdfpsEnrolled()); pw.println(" shouldListenForUdfps=" + shouldListenForFingerprint(true)); pw.println(" bouncerVisible=" + mBouncer); - pw.println(" mStatusBarState=" - + StatusBarState.toShortString(mStatusBarState)); + pw.println(" mStatusBarState=" + StatusBarState.toString(mStatusBarState)); } } if (mFaceManager != null && mFaceManager.isHardwareDetected()) { diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 6f0cd47a3f70..ea366eaf4568 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -394,7 +394,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme pw.println(" mUserUnlockedWithBiometric: " + mUserUnlockedWithBiometric); pw.println(" mRunningFPS: " + mRunningFPS); pw.println(" mCanDismissLockScreen: " + mCanDismissLockScreen); - pw.println(" mStatusBarState: " + StatusBarState.toShortString(mStatusBarState)); + pw.println(" mStatusBarState: " + StatusBarState.toString(mStatusBarState)); pw.println(" mQsExpanded: " + mQsExpanded); pw.println(" mInterpolatedDarkAmount: " + mInterpolatedDarkAmount); diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt index 22c69373336f..011881354e35 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt @@ -369,10 +369,15 @@ class ScreenDecorHwcLayer(context: Context, displayDecorationSupport: DisplayDec * Update the rounded corner size. */ fun updateRoundedCornerSize(top: Int, bottom: Int) { + if (roundedCornerTopSize == top && roundedCornerBottomSize == bottom) { + return + } roundedCornerTopSize = top roundedCornerBottomSize = bottom updateRoundedCornerDrawableBounds() - invalidate() + + // Use requestLayout() to trigger transparent region recalculated + requestLayout() } private fun updateRoundedCornerDrawableBounds() { diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 2ec9174caee6..ede2945be29a 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -1045,13 +1045,22 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab mExecutor.execute(() -> { if (mOverlays == null) return; if (SIZE.equals(key)) { + boolean hasReloadRoundedCornerRes = false; if (newValue != null) { try { mRoundedCornerResDelegate.updateTuningSizeFactor( Integer.parseInt(newValue)); + hasReloadRoundedCornerRes = true; } catch (Exception e) { } } + + // When onTuningChanged() is not called through updateRoundedCornerRadii(), + // we need to reload rounded corner res to prevent incorrect dimen + if (!hasReloadRoundedCornerRes) { + mRoundedCornerResDelegate.reloadAll(mDisplayUniqueId); + } + updateRoundedCornerSize( mRoundedCornerResDelegate.getTopRoundedSize(), mRoundedCornerResDelegate.getBottomRoundedSize()); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java index b8334a02e5f2..2a945ded08ef 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java @@ -185,7 +185,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud super.dump(fd, pw, args); pw.println("mShowingUdfpsBouncer=" + mShowingUdfpsBouncer); pw.println("mFaceDetectRunning=" + mFaceDetectRunning); - pw.println("mStatusBarState=" + StatusBarState.toShortString(mStatusBarState)); + pw.println("mStatusBarState=" + StatusBarState.toString(mStatusBarState)); pw.println("mQsExpanded=" + mQsExpanded); pw.println("mIsBouncerVisible=" + mIsBouncerVisible); pw.println("mInputBouncerHiddenAmount=" + mInputBouncerHiddenAmount); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java index be326da8d3bf..b325700954c2 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java @@ -77,7 +77,7 @@ class FalsingCollectorImpl implements FalsingCollector { new StatusBarStateController.StateListener() { @Override public void onStateChanged(int newState) { - logDebug("StatusBarState=" + StatusBarState.toShortString(newState)); + logDebug("StatusBarState=" + StatusBarState.toString(newState)); mState = newState; updateSessionActive(); } diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java index b60e26628c55..6a9317f2b543 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java @@ -17,11 +17,14 @@ package com.android.systemui.clipboardoverlay; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_ENABLED; +import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED; +import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED; import android.content.ClipboardManager; import android.content.Context; import android.provider.DeviceConfig; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.CoreStartable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.util.DeviceConfigProxy; @@ -38,15 +41,18 @@ public class ClipboardListener extends CoreStartable private final DeviceConfigProxy mDeviceConfig; private final ClipboardOverlayControllerFactory mOverlayFactory; private final ClipboardManager mClipboardManager; + private final UiEventLogger mUiEventLogger; private ClipboardOverlayController mClipboardOverlayController; @Inject public ClipboardListener(Context context, DeviceConfigProxy deviceConfigProxy, - ClipboardOverlayControllerFactory overlayFactory, ClipboardManager clipboardManager) { + ClipboardOverlayControllerFactory overlayFactory, ClipboardManager clipboardManager, + UiEventLogger uiEventLogger) { super(context); mDeviceConfig = deviceConfigProxy; mOverlayFactory = overlayFactory; mClipboardManager = clipboardManager; + mUiEventLogger = uiEventLogger; } @Override @@ -62,11 +68,15 @@ public class ClipboardListener extends CoreStartable if (!mClipboardManager.hasPrimaryClip()) { return; } + String clipSource = mClipboardManager.getPrimaryClipSource(); if (mClipboardOverlayController == null) { mClipboardOverlayController = mOverlayFactory.create(mContext); + mUiEventLogger.log(CLIPBOARD_OVERLAY_ENTERED, 0, clipSource); + } else { + mUiEventLogger.log(CLIPBOARD_OVERLAY_UPDATED, 0, clipSource); } mClipboardOverlayController.setClipData( - mClipboardManager.getPrimaryClip(), mClipboardManager.getPrimaryClipSource()); + mClipboardManager.getPrimaryClip(), clipSource); mClipboardOverlayController.setOnSessionCompleteListener(() -> { // Session is complete, free memory until it's needed again. mClipboardOverlayController = null; diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java index be2397d37bed..9861392ba463 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java @@ -21,6 +21,12 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT; +import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_TAPPED; +import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_EDIT_TAPPED; +import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED; +import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED; +import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TIMED_OUT; + import static java.util.Objects.requireNonNull; import android.animation.Animator; @@ -71,6 +77,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import com.android.internal.logging.UiEventLogger; import com.android.internal.policy.PhoneWindow; import com.android.systemui.R; import com.android.systemui.screenshot.DraggableConstraintLayout; @@ -97,6 +104,7 @@ public class ClipboardOverlayController { private static final int SWIPE_PADDING_DP = 12; // extra padding around views to allow swipe private final Context mContext; + private final UiEventLogger mUiEventLogger; private final DisplayManager mDisplayManager; private final DisplayMetrics mDisplayMetrics; private final WindowManager mWindowManager; @@ -129,11 +137,14 @@ public class ClipboardOverlayController { private boolean mBlockAttach = false; - public ClipboardOverlayController(Context context, TimeoutHandler timeoutHandler) { + public ClipboardOverlayController( + Context context, TimeoutHandler timeoutHandler, UiEventLogger uiEventLogger) { mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class)); final Context displayContext = context.createDisplayContext(getDefaultDisplay()); mContext = displayContext.createWindowContext(TYPE_SCREENSHOT, null); + mUiEventLogger = uiEventLogger; + mAccessibilityManager = AccessibilityManager.getInstance(mContext); mTextClassifier = requireNonNull(context.getSystemService(TextClassificationManager.class)) .getTextClassifier(); @@ -175,6 +186,7 @@ public class ClipboardOverlayController { @Override public void onSwipeDismissInitiated(Animator animator) { + mUiEventLogger.log(CLIPBOARD_OVERLAY_SWIPE_DISMISSED); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { @@ -222,7 +234,10 @@ public class ClipboardOverlayController { mView.post(this::animateIn); }); - mTimeoutHandler.setOnTimeoutRunnable(this::animateOut); + mTimeoutHandler.setOnTimeoutRunnable(() -> { + mUiEventLogger.log(CLIPBOARD_OVERLAY_TIMED_OUT); + animateOut(); + }); mCloseDialogsReceiver = new BroadcastReceiver() { @Override @@ -306,7 +321,10 @@ public class ClipboardOverlayController { chip.setText(action.getTitle()); chip.setContentDescription(action.getTitle()); chip.setIcon(action.getIcon(), false); - chip.setPendingIntent(action.getActionIntent(), this::animateOut); + chip.setPendingIntent(action.getActionIntent(), () -> { + mUiEventLogger.log(CLIPBOARD_OVERLAY_ACTION_TAPPED); + animateOut(); + }); chip.setAlpha(1); return chip; } @@ -350,6 +368,7 @@ public class ClipboardOverlayController { } private void editImage(Uri uri) { + mUiEventLogger.log(CLIPBOARD_OVERLAY_EDIT_TAPPED); String editorPackage = mContext.getString(R.string.config_screenshotEditor); Intent editIntent = new Intent(Intent.ACTION_EDIT); if (!TextUtils.isEmpty(editorPackage)) { @@ -363,6 +382,7 @@ public class ClipboardOverlayController { } private void editText() { + mUiEventLogger.log(CLIPBOARD_OVERLAY_EDIT_TAPPED); Intent editIntent = new Intent(mContext, EditTextActivity.class); editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); mContext.startActivity(editIntent); @@ -370,6 +390,7 @@ public class ClipboardOverlayController { } private void showNearby() { + mUiEventLogger.log(CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED); mContext.startActivity(getRemoteCopyIntent()); animateOut(); } diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerFactory.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerFactory.java index e1c11c4e8b4d..275d295613f9 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerFactory.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerFactory.java @@ -18,6 +18,7 @@ package com.android.systemui.clipboardoverlay; import android.content.Context; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.screenshot.TimeoutHandler; @@ -28,14 +29,17 @@ import javax.inject.Inject; */ @SysUISingleton public class ClipboardOverlayControllerFactory { + private final UiEventLogger mUiEventLogger; @Inject - public ClipboardOverlayControllerFactory() {} + public ClipboardOverlayControllerFactory(UiEventLogger uiEventLogger) { + mUiEventLogger = uiEventLogger; + } /** * One new ClipboardOverlayController, coming right up! */ public ClipboardOverlayController create(Context context) { - return new ClipboardOverlayController(context, new TimeoutHandler(context)); + return new ClipboardOverlayController(context, new TimeoutHandler(context), mUiEventLogger); } } diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayEvent.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayEvent.java new file mode 100644 index 000000000000..5604a9128261 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayEvent.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.clipboardoverlay; + +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; + +public enum ClipboardOverlayEvent implements UiEventLogger.UiEventEnum { + @UiEvent(doc = "clipboard overlay entered") + CLIPBOARD_OVERLAY_ENTERED(949), + @UiEvent(doc = "clipboard overlay updated") + CLIPBOARD_OVERLAY_UPDATED(950), + @UiEvent(doc = "clipboard edit tapped") + CLIPBOARD_OVERLAY_EDIT_TAPPED(951), + @UiEvent(doc = "clipboard action tapped") + CLIPBOARD_OVERLAY_ACTION_TAPPED(952), + @UiEvent(doc = "clipboard remote copy tapped") + CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED(953), + @UiEvent(doc = "clipboard overlay timed out") + CLIPBOARD_OVERLAY_TIMED_OUT(954), + @UiEvent(doc = "clipboard overlay dismiss tapped") + CLIPBOARD_OVERLAY_DISMISS_TAPPED(955), + @UiEvent(doc = "clipboard overlay swipe dismissed") + CLIPBOARD_OVERLAY_SWIPE_DISMISSED(956); + + private final int mId; + + ClipboardOverlayEvent(int id) { + mId = id; + } + + @Override + public int getId() { + return mId; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index f6aeb2ac4ebc..041de05aa3d4 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -36,6 +36,7 @@ import android.view.IWindowManager; import android.view.LayoutInflater; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; import com.android.internal.util.NotificationMessagingUtil; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; @@ -296,7 +297,8 @@ public class DependencyProvider { /***/ @Provides @SysUISingleton - public ClipboardOverlayControllerFactory provideClipboardOverlayControllerFactory() { - return new ClipboardOverlayControllerFactory(); + public ClipboardOverlayControllerFactory provideClipboardOverlayControllerFactory( + UiEventLogger uiEventLogger) { + return new ClipboardOverlayControllerFactory(uiEventLogger); } } diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt index c817f89c7a9b..4c444175eca1 100644 --- a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt @@ -56,17 +56,17 @@ class RoundedCornerResDelegate( private set init { - reloadDrawables() + reloadRes() reloadMeasures() } fun reloadAll(newDisplayUniqueId: String?) { displayUniqueId = newDisplayUniqueId - reloadDrawables() + reloadRes() reloadMeasures() } - private fun reloadDrawables() { + private fun reloadRes() { val configIdx = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId) isMultipleRadius = getIsMultipleRadius(configIdx) @@ -85,34 +85,6 @@ class RoundedCornerResDelegate( arrayResId = R.array.config_roundedCornerBottomDrawableArray, backupDrawableId = R.drawable.rounded_corner_bottom ) ?: roundedDrawable - - // If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the - // (width, height) size of drawable/rounded.xml instead of rounded_corner_radius - if (isMultipleRadius) { - roundedSize = Size( - roundedDrawable?.intrinsicWidth ?: 0, - roundedDrawable?.intrinsicHeight ?: 0) - topRoundedDrawable?.let { - topRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight) - } - bottomRoundedDrawable?.let { - bottomRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight) - } - } else { - val defaultRadius = RoundedCorners.getRoundedCornerRadius(res, displayUniqueId) - val topRadius = RoundedCorners.getRoundedCornerTopRadius(res, displayUniqueId) - val bottomRadius = RoundedCorners.getRoundedCornerBottomRadius(res, displayUniqueId) - roundedSize = Size(defaultRadius, defaultRadius) - topRoundedSize = Size(topRadius, topRadius) - bottomRoundedSize = Size(bottomRadius, bottomRadius) - } - - if (topRoundedSize.width == 0) { - topRoundedSize = roundedSize - } - if (bottomRoundedSize.width == 0) { - bottomRoundedSize = roundedSize - } } private fun reloadMeasures(roundedSizeFactor: Int? = null) { @@ -137,17 +109,18 @@ class RoundedCornerResDelegate( bottomRoundedSize = Size(bottomRadius, bottomRadius) } - roundedSizeFactor ?.let { - val length: Int = (it * density).toInt() - roundedSize = Size(length, length) - } - if (topRoundedSize.width == 0) { topRoundedSize = roundedSize } if (bottomRoundedSize.width == 0) { bottomRoundedSize = roundedSize } + + if (roundedSizeFactor != null && roundedSizeFactor > 0) { + val length: Int = (roundedSizeFactor * density).toInt() + topRoundedSize = Size(length, length) + bottomRoundedSize = Size(length, length) + } } fun updateTuningSizeFactor(factor: Int) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index 88555edd1e8b..b96eee717260 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -102,7 +102,7 @@ public class KeyguardService extends Service { "persist.wm.enable_remote_keyguard_animation"; private static final int sEnableRemoteKeyguardAnimation = - SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 1); + SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 2); /** * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 0486fee4239d..890ddf0d6cac 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -47,6 +47,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; +import android.graphics.Matrix; import android.hardware.biometrics.BiometricSourceType; import android.media.AudioAttributes; import android.media.AudioManager; @@ -236,6 +237,14 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, */ private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000; + private static final int UNOCCLUDE_ANIMATION_DURATION = 250; + + /** + * How far down to animate the unoccluding activity, in terms of percent of the activity's + * height. + */ + private static final float UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT = 0.1f; + /** * Boolean option for doKeyguardLocked/doKeyguardTimeout which, when set to true, forces the * keyguard to show even if it is disabled for the current user. @@ -883,53 +892,91 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, } }; + private IRemoteAnimationRunner mOccludeAnimationRunner = + new ActivityLaunchRemoteAnimationRunner(mOccludeAnimationController); + /** - * Animation controller for activities that unocclude the keyguard. This will play the launch - * animation in reverse. + * Animation controller for activities that unocclude the keyguard. This does not use the + * ActivityLaunchAnimator since we're just translating down, rather than emerging from a view + * or the power button. */ - private final ActivityLaunchAnimator.Controller mUnoccludeAnimationController = - new ActivityLaunchAnimator.Controller() { - @Override - public void onLaunchAnimationEnd(boolean isExpandingFullyAbove) { - setOccluded(false /* isOccluded */, false /* animate */); - } + private final IRemoteAnimationRunner mUnoccludeAnimationRunner = + new IRemoteAnimationRunner.Stub() { - @Override - public void onLaunchAnimationCancelled() { - setOccluded(false /* isOccluded */, false /* animate */); - } + @Nullable private ValueAnimator mUnoccludeAnimator; + private final Matrix mUnoccludeMatrix = new Matrix(); - @NonNull @Override - public ViewGroup getLaunchContainer() { - return ((ViewGroup) mKeyguardViewControllerLazy.get() - .getViewRootImpl().getView()); + public void onAnimationCancelled() { + if (mUnoccludeAnimator != null) { + mUnoccludeAnimator.cancel(); + } } @Override - public void setLaunchContainer(@NonNull ViewGroup launchContainer) { - // No-op, launch container is always the shade. - Log.wtf(TAG, "Someone tried to change the launch container for the " - + "ActivityLaunchAnimator, which should never happen."); - } + public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, + RemoteAnimationTarget[] wallpapers, + RemoteAnimationTarget[] nonApps, + IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { + final RemoteAnimationTarget primary = apps[0]; - @NonNull - @Override - public LaunchAnimator.State createAnimatorState() { - final int width = getLaunchContainer().getWidth(); - final int height = getLaunchContainer().getHeight(); + if (primary == null) { + finishedCallback.onAnimationFinished(); + return; + } - // TODO(b/207399883): Unocclude animation. This currently ends instantly. - return new LaunchAnimator.State( - 0, height, 0, width, mWindowCornerRadius, mWindowCornerRadius); + final SyncRtSurfaceTransactionApplier applier = + new SyncRtSurfaceTransactionApplier( + mKeyguardViewControllerLazy.get().getViewRootImpl().getView()); + + + mContext.getMainExecutor().execute(() -> { + if (mUnoccludeAnimator != null) { + mUnoccludeAnimator.cancel(); + } + + mUnoccludeAnimator = ValueAnimator.ofFloat(1f, 0f); + mUnoccludeAnimator.setDuration(UNOCCLUDE_ANIMATION_DURATION); + mUnoccludeAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE); + mUnoccludeAnimator.addUpdateListener( + animation -> { + final float animatedValue = + (float) animation.getAnimatedValue(); + + final float surfaceHeight = primary.screenSpaceBounds.height(); + + mUnoccludeMatrix.setTranslate( + 0f, + (1f - animatedValue) + * surfaceHeight + * UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT); + + SyncRtSurfaceTransactionApplier.SurfaceParams params = + new SyncRtSurfaceTransactionApplier.SurfaceParams + .Builder(primary.leash) + .withMatrix(mUnoccludeMatrix) + .withCornerRadius(mWindowCornerRadius) + .withAlpha(animatedValue) + .build(); + applier.scheduleApply(params); + }); + mUnoccludeAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + try { + finishedCallback.onAnimationFinished(); + mUnoccludeAnimator = null; + } catch (RemoteException e) { + e.printStackTrace(); + } + } + }); + + mUnoccludeAnimator.start(); + }); } }; - private IRemoteAnimationRunner mOccludeAnimationRunner = - new ActivityLaunchRemoteAnimationRunner(mOccludeAnimationController); - private IRemoteAnimationRunner mUnoccludeAnimationRunner = - new ActivityLaunchRemoteAnimationRunner(mUnoccludeAnimationController); - private DeviceConfigProxy mDeviceConfig; private DozeParameters mDozeParameters; diff --git a/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt b/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt index f1058e28863a..fbd17d7a212e 100644 --- a/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt +++ b/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt @@ -13,6 +13,7 @@ import android.graphics.PixelFormat import android.graphics.drawable.Drawable import android.os.SystemClock import androidx.annotation.VisibleForTesting +import com.android.internal.graphics.ColorUtils import com.android.systemui.animation.Interpolators import kotlin.math.abs import kotlin.math.cos @@ -157,8 +158,7 @@ class SquigglyProgress : Drawable() { } override fun setAlpha(alpha: Int) { - wavePaint.alpha = alpha - linePaint.alpha = (DISABLED_ALPHA * (alpha / 255f)).toInt() + updateColors(wavePaint.color, alpha) } override fun getAlpha(): Int { @@ -166,8 +166,7 @@ class SquigglyProgress : Drawable() { } override fun setTint(tintColor: Int) { - wavePaint.color = tintColor - linePaint.color = tintColor + updateColors(tintColor, alpha) } override fun onLevelChange(level: Int): Boolean { @@ -178,7 +177,12 @@ class SquigglyProgress : Drawable() { if (tint == null) { return } - wavePaint.color = tint.defaultColor - linePaint.color = tint.defaultColor + updateColors(tint.defaultColor, alpha) + } + + private fun updateColors(tintColor: Int, alpha: Int) { + wavePaint.color = ColorUtils.setAlphaComponent(tintColor, alpha) + linePaint.color = ColorUtils.setAlphaComponent(tintColor, + (DISABLED_ALPHA * (alpha / 255f)).toInt()) } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java index a1258df7a12c..03652412c129 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java @@ -480,7 +480,9 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl public void onMotionEvent(MotionEvent event) { if (mBackAnimation != null) { mBackAnimation.onBackMotion( - event, mIsLeftPanel ? BackEvent.EDGE_LEFT : BackEvent.EDGE_RIGHT); + event, + event.getActionMasked(), + mIsLeftPanel ? BackEvent.EDGE_LEFT : BackEvent.EDGE_RIGHT); } if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index 8d0494afbb89..7f49bcd9d926 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -26,6 +26,7 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; import android.os.Trace; +import android.util.IndentingPrintWriter; import android.util.Log; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; @@ -38,6 +39,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.keyguard.BouncerPanelExpansionCalculator; +import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.animation.ShadeInterpolation; @@ -58,13 +60,16 @@ import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.util.LifecycleFragment; import com.android.systemui.util.Utils; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Arrays; import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Named; public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Callbacks, - StatusBarStateController.StateListener { + StatusBarStateController.StateListener, Dumpable { private static final String TAG = "QS"; private static final boolean DEBUG = false; private static final String EXTRA_EXPANDED = "expanded"; @@ -135,7 +140,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca */ private boolean mAnimateNextQsUpdate; - private DumpManager mDumpManager; + private final DumpManager mDumpManager; /** * Progress of pull down from the center of the lock screen. @@ -256,15 +261,26 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca } @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mDumpManager.registerDumpable(getClass().getName(), this); + } + + @Override public void onDestroy() { super.onDestroy(); mStatusBarStateController.removeCallback(this); if (mListening) { setListening(false); } - mQSCustomizerController.setQs(null); + if (mQSCustomizerController != null) { + mQSCustomizerController.setQs(null); + } mScrollListener = null; - mDumpManager.unregisterDumpable(mContainer.getClass().getName()); + if (mContainer != null) { + mDumpManager.unregisterDumpable(mContainer.getClass().getName()); + } + mDumpManager.unregisterDumpable(getClass().getName()); } @Override @@ -272,7 +288,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca super.onSaveInstanceState(outState); outState.putBoolean(EXTRA_EXPANDED, mQsExpanded); outState.putBoolean(EXTRA_LISTENING, mListening); - mQSCustomizerController.saveInstanceState(outState); + if (mQSCustomizerController != null) { + mQSCustomizerController.saveInstanceState(outState); + } if (mQsExpanded) { mQSPanelController.getTileLayout().saveInstanceState(outState); } @@ -594,7 +612,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca } else if (progress > 0 && view.getVisibility() != View.VISIBLE) { view.setVisibility((View.VISIBLE)); } - float alpha = (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) + float alpha = mQSPanelController.bouncerInTransit() ? BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(progress) : ShadeInterpolation.getContentAlpha(progress); view.setAlpha(alpha); @@ -787,4 +805,62 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca setKeyguardShowing(newState == StatusBarState.KEYGUARD); updateShowCollapsedOnKeyguard(); } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + IndentingPrintWriter indentingPw = new IndentingPrintWriter(pw, /* singleIndent= */ " "); + indentingPw.println("QSFragment:"); + indentingPw.increaseIndent(); + indentingPw.println("mQsBounds: " + mQsBounds); + indentingPw.println("mQsExpanded: " + mQsExpanded); + indentingPw.println("mHeaderAnimating: " + mHeaderAnimating); + indentingPw.println("mStackScrollerOverscrolling: " + mStackScrollerOverscrolling); + indentingPw.println("mListening: " + mListening); + indentingPw.println("mLayoutDirection: " + mLayoutDirection); + indentingPw.println("mLastQSExpansion: " + mLastQSExpansion); + indentingPw.println("mLastPanelFraction: " + mLastPanelFraction); + indentingPw.println("mSquishinessFraction: " + mSquishinessFraction); + indentingPw.println("mQsDisabled: " + mQsDisabled); + indentingPw.println("mTemp: " + Arrays.toString(mTemp)); + indentingPw.println("mShowCollapsedOnKeyguard: " + mShowCollapsedOnKeyguard); + indentingPw.println("mLastKeyguardAndExpanded: " + mLastKeyguardAndExpanded); + indentingPw.println("mState: " + StatusBarState.toString(mState)); + indentingPw.println("mTmpLocation: " + Arrays.toString(mTmpLocation)); + indentingPw.println("mLastViewHeight: " + mLastViewHeight); + indentingPw.println("mLastHeaderTranslation: " + mLastHeaderTranslation); + indentingPw.println("mInSplitShade: " + mInSplitShade); + indentingPw.println("mTransitioningToFullShade: " + mTransitioningToFullShade); + indentingPw.println("mFullShadeProgress: " + mFullShadeProgress); + indentingPw.println("mOverScrolling: " + mOverScrolling); + indentingPw.println("isCustomizing: " + mQSCustomizerController.isCustomizing()); + View view = getView(); + if (view != null) { + indentingPw.println("top: " + view.getTop()); + indentingPw.println("y: " + view.getY()); + indentingPw.println("translationY: " + view.getTranslationY()); + indentingPw.println("alpha: " + view.getAlpha()); + indentingPw.println("height: " + view.getHeight()); + indentingPw.println("measuredHeight: " + view.getMeasuredHeight()); + indentingPw.println("clipBounds: " + view.getClipBounds()); + } else { + indentingPw.println("getView(): null"); + } + QuickStatusBarHeader header = mHeader; + if (header != null) { + indentingPw.println("headerHeight: " + header.getHeight()); + indentingPw.println("Header visibility: " + visibilityToString(header.getVisibility())); + } else { + indentingPw.println("mHeader: null"); + } + } + + private static String visibilityToString(int visibility) { + if (visibility == View.VISIBLE) { + return "VISIBLE"; + } + if (visibility == View.INVISIBLE) { + return "INVISIBLE"; + } + return "GONE"; + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java index dd2929c9a67a..10d792098608 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java @@ -43,6 +43,7 @@ import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.settings.brightness.BrightnessController; import com.android.systemui.settings.brightness.BrightnessMirrorHandler; import com.android.systemui.settings.brightness.BrightnessSliderController; +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.BrightnessMirrorController; import com.android.systemui.tuner.TunerService; @@ -65,6 +66,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> { private final BrightnessSliderController mBrightnessSliderController; private final BrightnessMirrorHandler mBrightnessMirrorHandler; private final FeatureFlags mFeatureFlags; + private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private boolean mGridContentVisible = true; @@ -101,7 +103,8 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> { DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory, BrightnessSliderController.Factory brightnessSliderFactory, - FalsingManager falsingManager, FeatureFlags featureFlags) { + FalsingManager falsingManager, FeatureFlags featureFlags, + StatusBarKeyguardViewManager statusBarKeyguardViewManager) { super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger, uiEventLogger, qsLogger, dumpManager); mQSFgsManagerFooter = qsFgsManagerFooter; @@ -117,6 +120,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> { mBrightnessController = brightnessControllerFactory.create(mBrightnessSliderController); mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController); mFeatureFlags = featureFlags; + mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; view.setUseNewFooter(featureFlags.isEnabled(Flags.NEW_FOOTER)); } @@ -281,5 +285,14 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> { void setPageMargin(int pageMargin) { mView.setPageMargin(pageMargin); } + + /** + * Determines if bouncer expansion is between 0 and 1 non-inclusive. + * + * @return if bouncer is in transit + */ + public boolean bouncerInTransit() { + return mStatusBarKeyguardViewManager.bouncerIsInTransit(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt index 5c1d332df7a7..86ef85824eb0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt @@ -73,7 +73,7 @@ class QSLogger @Inject constructor( log(DEBUG, { str1 = tileSpec int1 = statusBarState - str2 = StatusBarState.toShortString(statusBarState) + str2 = StatusBarState.toString(statusBarState) str3 = toStateString(state) }, { "[$str1] Tile clicked. StatusBarState=$str2. TileState=$str3" @@ -84,7 +84,7 @@ class QSLogger @Inject constructor( log(DEBUG, { str1 = tileSpec int1 = statusBarState - str2 = StatusBarState.toShortString(statusBarState) + str2 = StatusBarState.toString(statusBarState) str3 = toStateString(state) }, { "[$str1] Tile long clicked. StatusBarState=$str2. TileState=$str3" @@ -95,7 +95,7 @@ class QSLogger @Inject constructor( log(DEBUG, { str1 = tileSpec int1 = statusBarState - str2 = StatusBarState.toShortString(statusBarState) + str2 = StatusBarState.toString(statusBarState) str3 = toStateString(state) }, { "[$str1] Tile long clicked. StatusBarState=$str2. TileState=$str3" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java index 16bc951e0323..718bc5caf414 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java @@ -37,16 +37,19 @@ public class StatusBarState { */ public static final int SHADE_LOCKED = 2; - public static String toShortString(int x) { - switch (x) { + /** + * Returns the textual representation of the status bar state. + */ + public static String toString(int state) { + switch (state) { case SHADE: - return "SHD"; + return "SHADE"; case SHADE_LOCKED: - return "SHD_LCK"; + return "SHADE_LOCKED"; case KEYGUARD: - return "KGRD"; + return "KEYGUARD"; default: - return "bad_value_" + x; + return "UNKNOWN: " + state; } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index 2763bd711338..19f59f76f8a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -508,7 +508,7 @@ public class StatusBarStateControllerImpl implements * Returns String readable state of status bar from {@link StatusBarState} */ public static String describe(int state) { - return StatusBarState.toShortString(state); + return StatusBarState.toString(state); } @Override 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 32d37d18f407..c0553b5c3c2d 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 @@ -347,7 +347,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable setDimAmount((Float) animation.getAnimatedValue()); } }; - protected ViewGroup mQsContainer; + protected ViewGroup mQsHeader; + // Rect of QsHeader. Kept as a field just to avoid creating a new one each time. + private Rect mQsHeaderBound = new Rect(); private boolean mContinuousShadowUpdate; private boolean mContinuousBackgroundUpdate; private ViewTreeObserver.OnPreDrawListener mShadowUpdater @@ -1598,8 +1600,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } @ShadeViewRefactor(RefactorComponent.ADAPTER) - public void setQsContainer(ViewGroup qsContainer) { - mQsContainer = qsContainer; + public void setQsHeader(ViewGroup qsHeader) { + mQsHeader = qsHeader; } @ShadeViewRefactor(RefactorComponent.ADAPTER) @@ -3458,7 +3460,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable if (!isScrollingEnabled()) { return false; } - if (isInsideQsContainer(ev) && !mIsBeingDragged) { + if (isInsideQsHeader(ev) && !mIsBeingDragged) { return false; } mForcedScroll = null; @@ -3611,8 +3613,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } @ShadeViewRefactor(RefactorComponent.INPUT) - protected boolean isInsideQsContainer(MotionEvent ev) { - return ev.getY() < mQsContainer.getBottom(); + protected boolean isInsideQsHeader(MotionEvent ev) { + mQsHeader.getBoundsOnScreen(mQsHeaderBound); + return mQsHeaderBound.contains((int) ev.getX(), (int) ev.getY()); } @ShadeViewRefactor(RefactorComponent.INPUT) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 5bc50ae11fb7..3e630cdf8f97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -1234,8 +1234,9 @@ public class NotificationStackScrollLayoutController { mView.setExpandedHeight(expandedHeight); } - public void setQsContainer(ViewGroup view) { - mView.setQsContainer(view); + /** Sets the QS header. Used to check if a touch is within its bounds. */ + public void setQsHeader(ViewGroup view) { + mView.setQsHeader(view); } public void setAnimationsEnabled(boolean enabled) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 2d16b52839eb..11628cb75e87 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -3592,7 +3592,7 @@ public class NotificationPanelViewController extends PanelViewController { } }); mLockscreenShadeTransitionController.setQS(mQs); - mNotificationStackScrollLayoutController.setQsContainer((ViewGroup) mQs.getView()); + mNotificationStackScrollLayoutController.setQsHeader((ViewGroup) mQs.getHeader()); mQs.setScrollListener(mScrollListener); updateQsExpansion(); } 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 be50a17b8536..71f199f330a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -797,10 +797,9 @@ public abstract class PanelViewController { } mExpandedFraction = Math.min(1f, maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight); - mAmbientState.setExpansionFraction(mKeyguardStateController.isUnlocked() - ? mExpandedFraction - : BouncerPanelExpansionCalculator - .getBackScrimScaledExpansion(mExpandedFraction)); + mAmbientState.setExpansionFraction(mStatusBarKeyguardViewManager.bouncerIsInTransit() + ? BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(mExpandedFraction) + : mExpandedFraction); onHeightUpdated(mExpandedHeight); updatePanelExpansionAndVisibility(); }); 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 8272ed926255..a98ec58dc94c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -204,6 +204,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump private final Executor mMainExecutor; private final ScreenOffAnimationController mScreenOffAnimationController; private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; + private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private GradientColors mColors; private boolean mNeedsDrawableColorUpdate; @@ -266,7 +267,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump ConfigurationController configurationController, @Main Executor mainExecutor, ScreenOffAnimationController screenOffAnimationController, PanelExpansionStateManager panelExpansionStateManager, - KeyguardUnlockAnimationController keyguardUnlockAnimationController) { + KeyguardUnlockAnimationController keyguardUnlockAnimationController, + StatusBarKeyguardViewManager statusBarKeyguardViewManager) { mScrimStateListener = lightBarController::setScrimState; mDefaultScrimAlpha = BUSY_SCRIM_ALPHA; @@ -292,6 +294,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump keyguardStateController.getKeyguardFadingAwayDuration()); } }); + mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; configurationController.addCallback(new ConfigurationController.ConfigurationListener() { @Override public void onThemeChanged() { @@ -1021,6 +1024,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump if (aodWallpaperTimeout || occludedKeyguard) { mBehindAlpha = 1; } + // Prevent notification scrim flicker when transitioning away from keyguard. + if (mKeyguardStateController.isKeyguardGoingAway()) { + mNotificationsAlpha = 0; + } setScrimAlpha(mScrimInFront, mInFrontAlpha); setScrimAlpha(mScrimBehind, mBehindAlpha); setScrimAlpha(mNotificationsScrim, mNotificationsAlpha); @@ -1057,7 +1064,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump } private float getInterpolatedFraction() { - if (mState == ScrimState.KEYGUARD || mState == ScrimState.SHADE_LOCKED) { + if (mStatusBarKeyguardViewManager.bouncerIsInTransit()) { return BouncerPanelExpansionCalculator .getBackScrimScaledExpansion(mPanelExpansionFraction); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 23401618e1f3..a1cbba47e822 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -1368,6 +1368,15 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } /** + * Returns if bouncer expansion is between 0 and 1 non-inclusive. + */ + public boolean bouncerIsInTransit() { + if (mBouncer == null) return false; + + return mBouncer.inTransit(); + } + + /** * Delegate used to send show/reset events to an alternate authentication method instead of the * regular pin/pattern/password bouncer. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 8396639fe0f5..2c05a4ea8238 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -1155,7 +1155,8 @@ public class UserSwitcherController implements Dumpable { setButton(DialogInterface.BUTTON_POSITIVE, context.getString(mGuestUserAutoCreated ? com.android.settingslib.R.string.guest_reset_guest_confirm_button - : R.string.guest_exit_guest_dialog_remove), this); + : com.android.settingslib.R.string.guest_remove_guest_confirm_button), + this); SystemUIDialog.setWindowOnTop(this, mKeyguardStateController.isShowing()); setCanceledOnTouchOutside(false); mGuestId = guestId; diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index 85a6eebf6bd7..e4c83a543d89 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -49,7 +49,6 @@ import android.os.VibrationEffect; import android.provider.Settings; import android.service.notification.Condition; import android.service.notification.ZenModeConfig; -import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; @@ -418,41 +417,8 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa } private void onGetCaptionsComponentStateW(boolean fromTooltip) { - if (mCaptioningManager.isSystemAudioCaptioningUiEnabled()) { - mCallbacks.onCaptionComponentStateChanged(true, fromTooltip); - return; - } - - // TODO(b/220968335): Remove this check once system captions component migrates - // to new CaptioningManager APIs. - try { - String componentNameString = mContext.getString( - com.android.internal.R.string.config_defaultSystemCaptionsService); - if (TextUtils.isEmpty(componentNameString)) { - // component doesn't exist - mCallbacks.onCaptionComponentStateChanged(false, fromTooltip); - return; - } - - if (D.BUG) { - Log.i(TAG, String.format( - "isCaptionsServiceEnabled componentNameString=%s", componentNameString)); - } - - ComponentName componentName = ComponentName.unflattenFromString(componentNameString); - if (componentName == null) { - mCallbacks.onCaptionComponentStateChanged(false, fromTooltip); - return; - } - - mCallbacks.onCaptionComponentStateChanged( - mPackageManager.getComponentEnabledSetting(componentName) - == PackageManager.COMPONENT_ENABLED_STATE_ENABLED, fromTooltip); - } catch (Exception ex) { - Log.e(TAG, - "isCaptionsServiceEnabled failed to check for captions component", ex); - mCallbacks.onCaptionComponentStateChanged(false, fromTooltip); - } + mCallbacks.onCaptionComponentStateChanged( + mCaptioningManager.isSystemAudioCaptioningUiEnabled(), fromTooltip); } private void onAccessibilityModeChanged(Boolean showA11yStream) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java index e15b6cc62644..de04d3e9d059 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java @@ -32,6 +32,7 @@ import android.provider.DeviceConfig; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.util.DeviceConfigProxyFake; @@ -53,6 +54,8 @@ public class ClipboardListenerTest extends SysuiTestCase { private ClipboardOverlayControllerFactory mClipboardOverlayControllerFactory; @Mock private ClipboardOverlayController mOverlayController; + @Mock + private UiEventLogger mUiEventLogger; private DeviceConfigProxyFake mDeviceConfigProxy; private ClipData mSampleClipData; @@ -87,9 +90,10 @@ public class ClipboardListenerTest extends SysuiTestCase { mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED, "false", false); ClipboardListener listener = new ClipboardListener(getContext(), mDeviceConfigProxy, - mClipboardOverlayControllerFactory, mClipboardManager); + mClipboardOverlayControllerFactory, mClipboardManager, mUiEventLogger); listener.start(); verifyZeroInteractions(mClipboardManager); + verifyZeroInteractions(mUiEventLogger); } @Test @@ -97,9 +101,10 @@ public class ClipboardListenerTest extends SysuiTestCase { mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED, "true", false); ClipboardListener listener = new ClipboardListener(getContext(), mDeviceConfigProxy, - mClipboardOverlayControllerFactory, mClipboardManager); + mClipboardOverlayControllerFactory, mClipboardManager, mUiEventLogger); listener.start(); verify(mClipboardManager).addPrimaryClipChangedListener(any()); + verifyZeroInteractions(mUiEventLogger); } @Test @@ -107,7 +112,7 @@ public class ClipboardListenerTest extends SysuiTestCase { mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED, "true", false); ClipboardListener listener = new ClipboardListener(getContext(), mDeviceConfigProxy, - mClipboardOverlayControllerFactory, mClipboardManager); + mClipboardOverlayControllerFactory, mClipboardManager, mUiEventLogger); listener.start(); listener.onPrimaryClipChanged(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayEventTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayEventTest.java new file mode 100644 index 000000000000..c7c2cd8d7b4b --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayEventTest.java @@ -0,0 +1,93 @@ +/* + * 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.clipboardoverlay; + +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_ENABLED; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.provider.DeviceConfig; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.logging.UiEventLogger; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.util.DeviceConfigProxyFake; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class ClipboardOverlayEventTest extends SysuiTestCase { + + @Mock + private ClipboardManager mClipboardManager; + @Mock + private ClipboardOverlayControllerFactory mClipboardOverlayControllerFactory; + @Mock + private ClipboardOverlayController mOverlayController; + @Mock + private UiEventLogger mUiEventLogger; + + private final String mSampleSource = "Example source"; + + private ClipboardListener mClipboardListener; + + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + when(mClipboardOverlayControllerFactory.create(any())).thenReturn( + mOverlayController); + when(mClipboardManager.hasPrimaryClip()).thenReturn(true); + + ClipData sampleClipData = new ClipData("Test", new String[]{"text/plain"}, + new ClipData.Item("Test Item")); + when(mClipboardManager.getPrimaryClip()).thenReturn(sampleClipData); + when(mClipboardManager.getPrimaryClipSource()).thenReturn(mSampleSource); + + DeviceConfigProxyFake deviceConfigProxy = new DeviceConfigProxyFake(); + deviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED, + "true", false); + + mClipboardListener = new ClipboardListener(getContext(), deviceConfigProxy, + mClipboardOverlayControllerFactory, mClipboardManager, mUiEventLogger); + } + + @Test + public void test_enterAndReenter() { + mClipboardListener.start(); + + mClipboardListener.onPrimaryClipChanged(); + mClipboardListener.onPrimaryClipChanged(); + + verify(mUiEventLogger, times(1)).log( + ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED, 0, mSampleSource); + verify(mUiEventLogger, times(1)).log( + ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED, 0, mSampleSource); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt index b536bfdb944e..2effaec58a86 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt @@ -75,7 +75,7 @@ class RoundedCornerResDelegateTest : SysuiTestCase() { fun testUpdateTuningSizeFactor() { mContext.orCreateTestableResources.addOverrides( mockTypeArray = mockTypedArray, - radiusTop = 0, + radiusTop = 2, radiusBottom = 0, multipleRadius = false) diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java index 629c531f0a56..74cf49758ac6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java @@ -166,6 +166,76 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { } /** + * Makes sure swiping up when bouncer initially showing doesn't change the expansion amount. + */ + @Test + public void testSwipeUp_whenBouncerInitiallyShowing_keepsExpansionAtZero() { + when(mCentralSurfaces.isBouncerShowing()).thenReturn(true); + + mTouchHandler.onSessionStart(mTouchSession); + ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor = + ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class); + verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture()); + + final OnGestureListener gestureListener = gestureListenerCaptor.getValue(); + + final float percent = .3f; + final float distanceY = SCREEN_HEIGHT_PX * percent; + + // Swiping up near the top of the screen where the touch initiation region is. + final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, + 0, distanceY, 0); + final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, + 0, 0, 0); + + assertThat(gestureListener.onScroll(event1, event2, 0, distanceY)) + .isTrue(); + + // Ensure only called once + verify(mStatusBarKeyguardViewManager) + .onPanelExpansionChanged(anyFloat(), anyBoolean(), anyBoolean()); + + // TODO(b/227348372): update the logic and also this test. + // Ensure the expansion is kept at 0. + verify(mStatusBarKeyguardViewManager).onPanelExpansionChanged(eq(0f), eq(false), + eq(true)); + } + + /** + * Makes sure swiping down when bouncer initially hidden doesn't change the expansion amount. + */ + @Test + public void testSwipeDown_whenBouncerInitiallyHidden_keepsExpansionAtOne() { + mTouchHandler.onSessionStart(mTouchSession); + ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor = + ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class); + verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture()); + + final OnGestureListener gestureListener = gestureListenerCaptor.getValue(); + + final float percent = .15f; + final float distanceY = SCREEN_HEIGHT_PX * percent; + + // Swiping down near the bottom of the screen where the touch initiation region is. + final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, + 0, SCREEN_HEIGHT_PX - distanceY, 0); + final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, + 0, SCREEN_HEIGHT_PX, 0); + + assertThat(gestureListener.onScroll(event1, event2, 0, distanceY)) + .isTrue(); + + // Ensure only called once + verify(mStatusBarKeyguardViewManager) + .onPanelExpansionChanged(anyFloat(), anyBoolean(), anyBoolean()); + + // TODO(b/227348372): update the logic and also this test. + // Ensure the expansion is kept at 1. + verify(mStatusBarKeyguardViewManager).onPanelExpansionChanged(eq(1f), eq(false), + eq(true)); + } + + /** * Makes sure the expansion amount is proportional to (1 - scroll). */ @Test @@ -176,12 +246,13 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture()); final OnGestureListener gestureListener = gestureListenerCaptor.getValue(); - verifyScroll(.3f, Direction.UP, true, gestureListener); + + verifyScroll(.3f, Direction.UP, false, gestureListener); // Ensure that subsequent gestures are treated as expanding even if the bouncer state // changes. when(mCentralSurfaces.isBouncerShowing()).thenReturn(true); - verifyScroll(.7f, Direction.UP, true, gestureListener); + verifyScroll(.7f, Direction.UP, false, gestureListener); } /** @@ -197,17 +268,17 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture()); final OnGestureListener gestureListener = gestureListenerCaptor.getValue(); - verifyScroll(.3f, Direction.DOWN, false, gestureListener); + + verifyScroll(.3f, Direction.DOWN, true, gestureListener); // Ensure that subsequent gestures are treated as collapsing even if the bouncer state // changes. when(mCentralSurfaces.isBouncerShowing()).thenReturn(false); - verifyScroll(.7f, Direction.DOWN, false, gestureListener); + verifyScroll(.7f, Direction.DOWN, true, gestureListener); } - private void verifyScroll(float percent, Direction direction, boolean expanding, - android.view.GestureDetector.OnGestureListener gestureListener) { - + private void verifyScroll(float percent, Direction direction, + boolean isBouncerInitiallyShowing, GestureDetector.OnGestureListener gestureListener) { final float distanceY = SCREEN_HEIGHT_PX * percent; final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, @@ -223,10 +294,11 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { verify(mStatusBarKeyguardViewManager) .onPanelExpansionChanged(anyFloat(), anyBoolean(), anyBoolean()); + final float expansion = isBouncerInitiallyShowing ? percent : 1 - percent; + // Ensure correct expansion passed in. - verify(mStatusBarKeyguardViewManager) - .onPanelExpansionChanged( - eq(expanding ? 1 - percent : percent), eq(false), eq(true)); + verify(mStatusBarKeyguardViewManager).onPanelExpansionChanged(eq(expansion), eq(false), + eq(true)); } /** @@ -340,9 +412,9 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { mTouchHandler.onSessionStart(mTouchSession); ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor = ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class); + verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture()); ArgumentCaptor<InputChannelCompat.InputEventListener> inputEventListenerCaptor = ArgumentCaptor.forClass(InputChannelCompat.InputEventListener.class); - verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture()); verify(mTouchSession).registerInputListener(inputEventListenerCaptor.capture()); when(mVelocityTracker.getYVelocity()).thenReturn(velocityY); diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt index 0787fd65eae1..e3cd90b13422 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt @@ -8,6 +8,7 @@ import android.graphics.Rect import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest +import com.android.internal.graphics.ColorUtils import com.android.systemui.SysuiTestCase import com.android.systemui.util.mockito.any import com.google.common.truth.Truth.assertThat @@ -113,6 +114,7 @@ class SquigglyProgressTest : SysuiTestCase() { linePaintCaptor.capture()) assertThat(wavePaintCaptor.value.color).isEqualTo(tint) - assertThat(linePaintCaptor.value.color).isEqualTo(tint) + assertThat(linePaintCaptor.value.color).isEqualTo( + ColorUtils.setAlphaComponent(tint, DISABLED_ALPHA)) } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index 534c7e7f2029..777198b43d4a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -14,37 +14,41 @@ package com.android.systemui.qs; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.app.Fragment; import android.content.Context; +import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.testing.AndroidTestingRunner; -import android.testing.LayoutInflaterBuilder; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; +import android.view.LayoutInflater; import android.view.View; -import android.widget.FrameLayout; +import android.view.ViewGroup; import androidx.test.filters.SmallTest; -import androidx.test.filters.Suppress; -import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; -import com.android.keyguard.CarrierText; -import com.android.systemui.Dependency; +import com.android.keyguard.BouncerPanelExpansionCalculator; +import com.android.systemui.R; import com.android.systemui.SysuiBaseFragmentTest; +import com.android.systemui.animation.ShadeInterpolation; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; import com.android.systemui.media.MediaHost; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.qs.customize.QSCustomizerController; import com.android.systemui.qs.dagger.QSFragmentComponent; import com.android.systemui.qs.external.CustomTileStatePersister; import com.android.systemui.qs.external.TileLifecycleManager; @@ -54,19 +58,18 @@ import com.android.systemui.qs.tileimpl.QSFactoryImpl; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.phone.AutoTileManager; -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.phone.StatusBarIconController; -import com.android.systemui.statusbar.policy.Clock; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.tuner.TunerService; +import com.android.systemui.util.animation.UniqueObjectHostView; import com.android.systemui.util.settings.SecureSettings; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -75,77 +78,69 @@ import org.mockito.MockitoAnnotations; import java.util.Optional; @RunWith(AndroidTestingRunner.class) -@RunWithLooper +@RunWithLooper(setAsMainLooper = true) @SmallTest -@Suppress public class QSFragmentTest extends SysuiBaseFragmentTest { - private MetricsLogger mMockMetricsLogger; - @Mock - private QSFragmentComponent.Factory mQsComponentFactory; - @Mock - private QSFragmentComponent mQsFragmentComponent; - @Mock - private QSPanelController mQSPanelController; - @Mock - private MediaHost mQSMediaHost; - @Mock - private MediaHost mQQSMediaHost; - @Mock - private KeyguardBypassController mBypassController; - @Mock - private FalsingManager mFalsingManager; - @Mock - private TileServiceRequestController.Builder mTileServiceRequestControllerBuilder; - @Mock - private TileServiceRequestController mTileServiceRequestController; + @Mock private QSFragmentComponent.Factory mQsComponentFactory; + @Mock private QSFragmentComponent mQsFragmentComponent; + @Mock private QSPanelController mQSPanelController; + @Mock private MediaHost mQSMediaHost; + @Mock private MediaHost mQQSMediaHost; + @Mock private KeyguardBypassController mBypassController; + @Mock private FalsingManager mFalsingManager; + @Mock private TileServiceRequestController.Builder mTileServiceRequestControllerBuilder; + @Mock private TileServiceRequestController mTileServiceRequestController; + @Mock private QSCustomizerController mQsCustomizerController; + @Mock private QuickQSPanelController mQuickQSPanelController; + @Mock private FooterActionsController mQSFooterActionController; + @Mock private QSContainerImplController mQSContainerImplController; + @Mock private QSContainerImpl mContainer; + @Mock private QSFooter mFooter; + @Mock private LayoutInflater mLayoutInflater; + @Mock private NonInterceptingScrollView mQSPanelScrollView; + @Mock private QuickStatusBarHeader mHeader; + @Mock private QSPanel.QSTileLayout mQsTileLayout; + @Mock private QSPanel.QSTileLayout mQQsTileLayout; + @Mock private QSAnimator mQSAnimator; + private View mQsFragmentView; + @Mock private StatusBarStateController mStatusBarStateController; public QSFragmentTest() { super(QSFragment.class); - injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); } @Before - @Ignore("failing") - public void addLeakCheckDependencies() { - MockitoAnnotations.initMocks(this); - when(mQsComponentFactory.create(any(QSFragment.class))).thenReturn(mQsFragmentComponent); - when(mQsFragmentComponent.getQSPanelController()).thenReturn(mQSPanelController); - - when(mTileServiceRequestControllerBuilder.create(any())) - .thenReturn(mTileServiceRequestController); - - mMockMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class); - mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, - new LayoutInflaterBuilder(mContext) - .replace("com.android.systemui.statusbar.policy.SplitClockView", - FrameLayout.class) - .replace("TextClock", View.class) - .replace(CarrierText.class, View.class) - .replace(Clock.class, View.class) - .build()); - - mDependency.injectTestDependency(Dependency.BG_LOOPER, - TestableLooper.get(this).getLooper()); - mDependency.injectMockDependency(UserSwitcherController.class); + public void setup() { + injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); } @Test - @Ignore("failing") public void testListening() { - assertEquals(Looper.myLooper(), Looper.getMainLooper()); QSFragment qs = (QSFragment) mFragment; mFragments.dispatchResume(); processAllMessages(); - QSTileHost host = new QSTileHost(mContext, mock(StatusBarIconController.class), - mock(QSFactoryImpl.class), new Handler(), Looper.myLooper(), - mock(PluginManager.class), mock(TunerService.class), - () -> mock(AutoTileManager.class), mock(DumpManager.class), - mock(BroadcastDispatcher.class), Optional.of(mock(CentralSurfaces.class)), - mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class), - mock(SecureSettings.class), mock(CustomTileStatePersister.class), - mTileServiceRequestControllerBuilder, mock(TileLifecycleManager.Factory.class)); + QSTileHost host = + new QSTileHost( + mContext, + mock(StatusBarIconController.class), + mock(QSFactoryImpl.class), + new Handler(), + Looper.myLooper(), + mock(PluginManager.class), + mock(TunerService.class), + () -> mock(AutoTileManager.class), + mock(DumpManager.class), + mock(BroadcastDispatcher.class), + Optional.of(mock(CentralSurfaces.class)), + mock(QSLogger.class), + mock(UiEventLogger.class), + mock(UserTracker.class), + mock(SecureSettings.class), + mock(CustomTileStatePersister.class), + mTileServiceRequestControllerBuilder, + mock(TileLifecycleManager.Factory.class)); qs.setListening(true); processAllMessages(); @@ -157,13 +152,11 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { } @Test - @Ignore("failing") public void testSaveState() { - QSFragment qs = (QSFragment) mFragment; - mFragments.dispatchResume(); processAllMessages(); + QSFragment qs = (QSFragment) mFragment; qs.setListening(true); qs.setExpanded(true); processAllMessages(); @@ -176,14 +169,91 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { assertTrue(qs.isExpanded()); } + @Test + public void transitionToFullShade_inSplitShade_setsAlphaBasedOnProgress() { + QSFragment fragment = resumeAndGetFragment(); + enableSplitShade(); + int transitionPxAmount = 123; + float transitionProgress = 0.5f; + + fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); + + assertThat(mQsFragmentView.getAlpha()) + .isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress)); + } + + @Test + public void + transitionToFullShade_inSplitShade_onKeyguard_bouncerNotActive_usesShadeInterpolator() { + QSFragment fragment = resumeAndGetFragment(); + enableSplitShade(); + setStatusBarState(StatusBarState.KEYGUARD); + when(mQSPanelController.bouncerInTransit()).thenReturn(false); + int transitionPxAmount = 123; + float transitionProgress = 0.5f; + + fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); + + assertThat(mQsFragmentView.getAlpha()) + .isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress)); + } + + @Test + public void + transitionToFullShade_inSplitShade_onKeyguard_bouncerActive_usesBouncerInterpolator() { + QSFragment fragment = resumeAndGetFragment(); + enableSplitShade(); + setStatusBarState(StatusBarState.KEYGUARD); + when(mQSPanelController.bouncerInTransit()).thenReturn(true); + int transitionPxAmount = 123; + float transitionProgress = 0.5f; + + fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); + + assertThat(mQsFragmentView.getAlpha()) + .isEqualTo( + BouncerPanelExpansionCalculator.getBackScrimScaledExpansion( + transitionProgress)); + } + + @Test + public void transitionToFullShade_notInSplitShade_alwaysSetsAlphaTo1() { + QSFragment fragment = resumeAndGetFragment(); + disableSplitShade(); + + int transitionPxAmount = 12; + float transitionProgress = 0.1f; + fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); + assertThat(mQsFragmentView.getAlpha()).isEqualTo(1); + + transitionPxAmount = 123; + transitionProgress = 0.5f; + fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); + assertThat(mQsFragmentView.getAlpha()).isEqualTo(1); + assertThat(mQsFragmentView.getAlpha()).isEqualTo(1); + + transitionPxAmount = 234; + transitionProgress = 0.7f; + fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress); + assertThat(mQsFragmentView.getAlpha()).isEqualTo(1); + } + @Override protected Fragment instantiate(Context context, String className, Bundle arguments) { + MockitoAnnotations.initMocks(this); CommandQueue commandQueue = new CommandQueue(context); + + setupQsComponent(); + setUpViews(); + setUpInflater(); + setUpMedia(); + setUpOther(); + return new QSFragment( - new RemoteInputQuickSettingsDisabler(context, commandQueue, - mock(ConfigurationController.class)), + new RemoteInputQuickSettingsDisabler( + context, commandQueue, mock(ConfigurationController.class)), mock(QSTileHost.class), - mock(StatusBarStateController.class), + mStatusBarStateController, commandQueue, mQSMediaHost, mQQSMediaHost, @@ -193,4 +263,73 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { mFalsingManager, mock(DumpManager.class)); } + + private void setUpOther() { + when(mTileServiceRequestControllerBuilder.create(any())) + .thenReturn(mTileServiceRequestController); + when(mQSContainerImplController.getView()).thenReturn(mContainer); + when(mQSPanelController.getTileLayout()).thenReturn(mQQsTileLayout); + when(mQuickQSPanelController.getTileLayout()).thenReturn(mQsTileLayout); + } + + private void setUpMedia() { + when(mQSMediaHost.getCurrentClipping()).thenReturn(new Rect()); + when(mQSMediaHost.getHostView()).thenReturn(new UniqueObjectHostView(mContext)); + when(mQQSMediaHost.getHostView()).thenReturn(new UniqueObjectHostView(mContext)); + } + + private void setUpViews() { + mQsFragmentView = spy(new View(mContext)); + when(mQsFragmentView.findViewById(R.id.expanded_qs_scroll_view)) + .thenReturn(mQSPanelScrollView); + when(mQsFragmentView.findViewById(R.id.header)).thenReturn(mHeader); + when(mQsFragmentView.findViewById(android.R.id.edit)).thenReturn(new View(mContext)); + } + + private void setUpInflater() { + when(mLayoutInflater.cloneInContext(any(Context.class))).thenReturn(mLayoutInflater); + when(mLayoutInflater.inflate(anyInt(), any(ViewGroup.class), anyBoolean())) + .thenReturn(mQsFragmentView); + mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, mLayoutInflater); + } + + private void setupQsComponent() { + when(mQsComponentFactory.create(any(QSFragment.class))).thenReturn(mQsFragmentComponent); + when(mQsFragmentComponent.getQSPanelController()).thenReturn(mQSPanelController); + when(mQsFragmentComponent.getQuickQSPanelController()).thenReturn(mQuickQSPanelController); + when(mQsFragmentComponent.getQSCustomizerController()).thenReturn(mQsCustomizerController); + when(mQsFragmentComponent.getQSContainerImplController()) + .thenReturn(mQSContainerImplController); + when(mQsFragmentComponent.getQSFooter()).thenReturn(mFooter); + when(mQsFragmentComponent.getQSFooterActionController()) + .thenReturn(mQSFooterActionController); + when(mQsFragmentComponent.getQSAnimator()).thenReturn(mQSAnimator); + } + + private QSFragment getFragment() { + return ((QSFragment) mFragment); + } + + private QSFragment resumeAndGetFragment() { + mFragments.dispatchResume(); + processAllMessages(); + return getFragment(); + } + + private void setStatusBarState(int statusBarState) { + when(mStatusBarStateController.getState()).thenReturn(statusBarState); + getFragment().onStateChanged(statusBarState); + } + + private void enableSplitShade() { + setSplitShadeEnabled(true); + } + + private void disableSplitShade() { + setSplitShadeEnabled(false); + } + + private void setSplitShadeEnabled(boolean enabled) { + getFragment().setInSplitShade(enabled); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt index e9488e9ad98c..58a070db9a95 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt @@ -15,7 +15,9 @@ import com.android.systemui.qs.customize.QSCustomizerController import com.android.systemui.qs.logging.QSLogger import com.android.systemui.settings.brightness.BrightnessController import com.android.systemui.settings.brightness.BrightnessSliderController +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager import com.android.systemui.tuner.TunerService +import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before import org.junit.Test @@ -52,6 +54,7 @@ class QSPanelControllerTest : SysuiTestCase() { @Mock private lateinit var mediaHost: MediaHost @Mock private lateinit var tile: QSTile @Mock private lateinit var otherTile: QSTile + @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager private lateinit var controller: QSPanelController @@ -62,6 +65,7 @@ class QSPanelControllerTest : SysuiTestCase() { whenever(brightnessSliderFactory.create(any(), any())).thenReturn(brightnessSlider) whenever(brightnessControllerFactory.create(any())).thenReturn(brightnessController) whenever(qsPanel.resources).thenReturn(mContext.orCreateTestableResources.resources) + whenever(statusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(false) controller = QSPanelController( qsPanel, @@ -80,7 +84,8 @@ class QSPanelControllerTest : SysuiTestCase() { brightnessControllerFactory, brightnessSliderFactory, falsingManager, - featureFlags + featureFlags, + statusBarKeyguardViewManager ) } @@ -109,4 +114,12 @@ class QSPanelControllerTest : SysuiTestCase() { verify(tile).refreshState() verify(otherTile, Mockito.never()).refreshState() } + + @Test + fun testBouncerIsInTransit() { + whenever(statusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(true) + assertThat(controller.bouncerInTransit()).isEqualTo(true) + whenever(statusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(false) + assertThat(controller.bouncerInTransit()).isEqualTo(false) + } } 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 5eef1df8c7a3..81a5f11b1553 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 @@ -119,6 +119,8 @@ public class ScrimControllerTest extends SysuiTestCase { // event-dispatch-on-registration pattern caused some of these unit tests to fail.) @Mock private PanelExpansionStateManager mPanelExpansionStateManager; + @Mock + private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private static class AnimatorListener implements Animator.AnimatorListener { @@ -233,7 +235,8 @@ public class ScrimControllerTest extends SysuiTestCase { mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()), mScreenOffAnimationController, mPanelExpansionStateManager, - mKeyguardUnlockAnimationController); + mKeyguardUnlockAnimationController, + mStatusBarKeyguardViewManager); mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible); mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront); mScrimController.setAnimatorListener(mAnimatorListener); @@ -1234,6 +1237,8 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void testNotificationTransparency_followsPanelExpansionInShadeLockedState() { + when(mStatusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(true); + mScrimController.transitionTo(ScrimState.SHADE_LOCKED); assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0f, /* expansion */ 0.8f); @@ -1242,6 +1247,8 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void testNotificationTransparency_unnocclusion() { + when(mStatusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(true); + mScrimController.transitionTo(ScrimState.KEYGUARD); mScrimController.setUnocclusionAnimationRunning(true); @@ -1255,6 +1262,8 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void testNotificationTransparency_inKeyguardState() { + when(mStatusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(true); + mScrimController.transitionTo(ScrimState.KEYGUARD); assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 1f, /* expansion */ 0.8f); @@ -1351,6 +1360,15 @@ public class ScrimControllerTest extends SysuiTestCase { )); } + @Test + public void keyguardGoingAwayUpdateScrims() { + when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true); + mScrimController.updateScrims(); + finishAnimationsImmediately(); + assertThat(mNotificationsScrim.getViewAlpha()).isEqualTo(TRANSPARENT); + } + + 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/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index ede3de83b572..90cbf540004e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -55,6 +55,8 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.unfold.SysUIUnfoldComponent; +import com.google.common.truth.Truth; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -434,4 +436,14 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { verify(mBouncer).updateKeyguardPosition(1.0f); } + + @Test + public void testBouncerIsInTransit() { + when(mBouncer.inTransit()).thenReturn(true); + Truth.assertThat(mStatusBarKeyguardViewManager.bouncerIsInTransit()).isTrue(); + when(mBouncer.inTransit()).thenReturn(false); + Truth.assertThat(mStatusBarKeyguardViewManager.bouncerIsInTransit()).isFalse(); + mBouncer = null; + Truth.assertThat(mStatusBarKeyguardViewManager.bouncerIsInTransit()).isFalse(); + } } diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index 06fd5c0e9b82..88ad62046b2b 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -23,6 +23,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_SECURE; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.StringRes; import android.app.Activity; @@ -34,7 +35,8 @@ import android.companion.virtual.IVirtualDevice; import android.companion.virtual.IVirtualDeviceActivityListener; import android.companion.virtual.VirtualDeviceManager.ActivityListener; import android.companion.virtual.VirtualDeviceParams; -import android.companion.virtual.audio.IAudioSessionCallback; +import android.companion.virtual.audio.IAudioConfigChangedCallback; +import android.companion.virtual.audio.IAudioRoutingCallback; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -269,7 +271,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) @Override // Binder call - public void onAudioSessionStarting(int displayId, IAudioSessionCallback callback) { + public void onAudioSessionStarting(int displayId, + @NonNull IAudioRoutingCallback routingCallback, + @Nullable IAudioConfigChangedCallback configChangedCallback) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CREATE_VIRTUAL_DEVICE, "Permission required to start audio session"); @@ -283,7 +287,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub if (mVirtualAudioController == null) { mVirtualAudioController = new VirtualAudioController(mContext); GenericWindowPolicyController gwpc = mWindowPolicyControllers.get(displayId); - mVirtualAudioController.startListening(gwpc, callback); + mVirtualAudioController.startListening(gwpc, routingCallback, + configChangedCallback); } } } diff --git a/services/companion/java/com/android/server/companion/virtual/audio/AudioPlaybackDetector.java b/services/companion/java/com/android/server/companion/virtual/audio/AudioPlaybackDetector.java index 2d7291300e23..6e82d6672cd4 100644 --- a/services/companion/java/com/android/server/companion/virtual/audio/AudioPlaybackDetector.java +++ b/services/companion/java/com/android/server/companion/virtual/audio/AudioPlaybackDetector.java @@ -51,8 +51,10 @@ final class AudioPlaybackDetector extends AudioManager.AudioPlaybackCallback { } void unregister() { - mAudioPlaybackCallback = null; - mAudioManager.unregisterAudioPlaybackCallback(/* cb= */ this); + if (mAudioPlaybackCallback != null) { + mAudioPlaybackCallback = null; + mAudioManager.unregisterAudioPlaybackCallback(/* cb= */ this); + } } @Override diff --git a/services/companion/java/com/android/server/companion/virtual/audio/AudioRecordingDetector.java b/services/companion/java/com/android/server/companion/virtual/audio/AudioRecordingDetector.java index c20414529f5b..54add2e1fc85 100644 --- a/services/companion/java/com/android/server/companion/virtual/audio/AudioRecordingDetector.java +++ b/services/companion/java/com/android/server/companion/virtual/audio/AudioRecordingDetector.java @@ -51,8 +51,10 @@ final class AudioRecordingDetector extends AudioManager.AudioRecordingCallback { } void unregister() { - mAudioRecordingCallback = null; - mAudioManager.unregisterAudioRecordingCallback(/* cb= */ this); + if (mAudioRecordingCallback != null) { + mAudioRecordingCallback = null; + mAudioManager.unregisterAudioRecordingCallback(/* cb= */ this); + } } @Override diff --git a/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java b/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java index 1dc87d68aeae..13a47d681729 100644 --- a/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java +++ b/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java @@ -21,7 +21,8 @@ import static android.media.AudioPlaybackConfiguration.PLAYER_STATE_STARTED; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.companion.virtual.audio.IAudioSessionCallback; +import android.companion.virtual.audio.IAudioConfigChangedCallback; +import android.companion.virtual.audio.IAudioRoutingCallback; import android.content.Context; import android.media.AudioManager; import android.media.AudioPlaybackConfiguration; @@ -64,9 +65,10 @@ public final class VirtualAudioController implements AudioPlaybackCallback, private ArraySet<Integer> mPlayingAppUids = new ArraySet<>(); private GenericWindowPolicyController mGenericWindowPolicyController; private final Object mCallbackLock = new Object(); - @Nullable @GuardedBy("mCallbackLock") - private IAudioSessionCallback mCallback; + private IAudioRoutingCallback mRoutingCallback; + @GuardedBy("mCallbackLock") + private IAudioConfigChangedCallback mConfigChangedCallback; public VirtualAudioController(Context context) { mContext = context; @@ -80,18 +82,22 @@ public final class VirtualAudioController implements AudioPlaybackCallback, */ public void startListening( @NonNull GenericWindowPolicyController genericWindowPolicyController, - @Nullable IAudioSessionCallback callback) { + @NonNull IAudioRoutingCallback routingCallback, + @Nullable IAudioConfigChangedCallback configChangedCallback) { mGenericWindowPolicyController = genericWindowPolicyController; mGenericWindowPolicyController.setRunningAppsChangedListener(/* listener= */ this); synchronized (mCallbackLock) { - mCallback = callback; + mRoutingCallback = routingCallback; + mConfigChangedCallback = configChangedCallback; } synchronized (mLock) { mRunningAppUids.clear(); mPlayingAppUids.clear(); } - mAudioPlaybackDetector.register(/* callback= */ this); - mAudioRecordingDetector.register(/* callback= */ this); + if (configChangedCallback != null) { + mAudioPlaybackDetector.register(/* callback= */ this); + mAudioRecordingDetector.register(/* callback= */ this); + } } /** @@ -109,7 +115,8 @@ public final class VirtualAudioController implements AudioPlaybackCallback, mGenericWindowPolicyController = null; } synchronized (mCallbackLock) { - mCallback = null; + mRoutingCallback = null; + mConfigChangedCallback = null; } } @@ -169,9 +176,9 @@ public final class VirtualAudioController implements AudioPlaybackCallback, audioPlaybackConfigurations = findPlaybackConfigurations(configs, mRunningAppUids); } synchronized (mCallbackLock) { - if (mCallback != null) { + if (mConfigChangedCallback != null) { try { - mCallback.onPlaybackConfigChanged(audioPlaybackConfigurations); + mConfigChangedCallback.onPlaybackConfigChanged(audioPlaybackConfigurations); } catch (RemoteException e) { Slog.e(TAG, "RemoteException when calling onPlaybackConfigChanged", e); } @@ -188,9 +195,9 @@ public final class VirtualAudioController implements AudioPlaybackCallback, audioRecordingConfigurations = findRecordingConfigurations(configs, mRunningAppUids); } synchronized (mCallbackLock) { - if (mCallback != null) { + if (mConfigChangedCallback != null) { try { - mCallback.onRecordingConfigChanged(audioRecordingConfigurations); + mConfigChangedCallback.onRecordingConfigChanged(audioRecordingConfigurations); } catch (RemoteException e) { Slog.e(TAG, "RemoteException when calling onRecordingConfigChanged", e); } @@ -227,9 +234,9 @@ public final class VirtualAudioController implements AudioPlaybackCallback, } synchronized (mCallbackLock) { - if (mCallback != null) { + if (mRoutingCallback != null) { try { - mCallback.onAppsNeedingAudioRoutingChanged(runningUids); + mRoutingCallback.onAppsNeedingAudioRoutingChanged(runningUids); } catch (RemoteException e) { Slog.e(TAG, "RemoteException when calling updateReroutingApps", e); } diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 68cd28809fd0..f34c5062144e 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -43,6 +43,7 @@ import android.util.ArraySet; import android.util.SparseArray; import com.android.internal.util.function.pooled.PooledLambda; +import com.android.server.pm.KnownPackages; import com.android.server.pm.PackageList; import com.android.server.pm.PackageSetting; import com.android.server.pm.dex.DynamicCodeLogger; @@ -68,51 +69,6 @@ import java.util.function.Consumer; * @hide Only for use within the system server. */ public abstract class PackageManagerInternal { - - @IntDef(prefix = "PACKAGE_", value = { - PACKAGE_SYSTEM, - PACKAGE_SETUP_WIZARD, - PACKAGE_INSTALLER, - PACKAGE_UNINSTALLER, - PACKAGE_VERIFIER, - PACKAGE_BROWSER, - PACKAGE_SYSTEM_TEXT_CLASSIFIER, - PACKAGE_PERMISSION_CONTROLLER, - PACKAGE_CONFIGURATOR, - PACKAGE_INCIDENT_REPORT_APPROVER, - PACKAGE_APP_PREDICTOR, - PACKAGE_OVERLAY_CONFIG_SIGNATURE, - PACKAGE_WIFI, - PACKAGE_COMPANION, - PACKAGE_RETAIL_DEMO, - PACKAGE_RECENTS, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface KnownPackage {} - - public static final int PACKAGE_SYSTEM = 0; - public static final int PACKAGE_SETUP_WIZARD = 1; - public static final int PACKAGE_INSTALLER = 2; - public static final int PACKAGE_UNINSTALLER = 3; - public static final int PACKAGE_VERIFIER = 4; - public static final int PACKAGE_BROWSER = 5; - public static final int PACKAGE_SYSTEM_TEXT_CLASSIFIER = 6; - public static final int PACKAGE_PERMISSION_CONTROLLER = 7; - public static final int PACKAGE_WELLBEING = 8; - public static final int PACKAGE_DOCUMENTER = 9; - public static final int PACKAGE_CONFIGURATOR = 10; - public static final int PACKAGE_INCIDENT_REPORT_APPROVER = 11; - public static final int PACKAGE_APP_PREDICTOR = 12; - public static final int PACKAGE_OVERLAY_CONFIG_SIGNATURE = 13; - public static final int PACKAGE_WIFI = 14; - public static final int PACKAGE_COMPANION = 15; - public static final int PACKAGE_RETAIL_DEMO = 16; - public static final int PACKAGE_RECENTS = 17; - public static final int PACKAGE_AMBIENT_CONTEXT_DETECTION = 18; - // Integer value of the last known package ID. Increases as new ID is added to KnownPackage. - // Please note the numbers should be continuous. - public static final int LAST_KNOWN_PACKAGE = PACKAGE_AMBIENT_CONTEXT_DETECTION; - @LongDef(flag = true, prefix = "RESOLVE_", value = { RESOLVE_NON_BROWSER_ONLY, RESOLVE_NON_RESOLVER_ONLY @@ -754,12 +710,11 @@ public abstract class PackageManagerInternal { */ public abstract boolean isResolveActivityComponent(@NonNull ComponentInfo component); - /** * Returns a list of package names for a known package */ public abstract @NonNull String[] getKnownPackageNames( - @KnownPackage int knownPackage, int userId); + @KnownPackages.KnownPackage int knownPackage, int userId); /** * Returns whether the package is an instant app. @@ -1143,55 +1098,6 @@ public abstract class PackageManagerInternal { @NonNull InstalledLoadingProgressCallback callback, int userId); /** - * Returns the string representation of a known package. For example, - * {@link #PACKAGE_SETUP_WIZARD} is represented by the string Setup Wizard. - * - * @param knownPackage The known package. - * @return The string representation. - */ - public static @NonNull String knownPackageToString(@KnownPackage int knownPackage) { - switch (knownPackage) { - case PACKAGE_SYSTEM: - return "System"; - case PACKAGE_SETUP_WIZARD: - return "Setup Wizard"; - case PACKAGE_INSTALLER: - return "Installer"; - case PACKAGE_UNINSTALLER: - return "Uninstaller"; - case PACKAGE_VERIFIER: - return "Verifier"; - case PACKAGE_BROWSER: - return "Browser"; - case PACKAGE_SYSTEM_TEXT_CLASSIFIER: - return "System Text Classifier"; - case PACKAGE_PERMISSION_CONTROLLER: - return "Permission Controller"; - case PACKAGE_WELLBEING: - return "Wellbeing"; - case PACKAGE_DOCUMENTER: - return "Documenter"; - case PACKAGE_CONFIGURATOR: - return "Configurator"; - case PACKAGE_INCIDENT_REPORT_APPROVER: - return "Incident Report Approver"; - case PACKAGE_APP_PREDICTOR: - return "App Predictor"; - case PACKAGE_WIFI: - return "Wi-Fi"; - case PACKAGE_COMPANION: - return "Companion"; - case PACKAGE_RETAIL_DEMO: - return "Retail Demo"; - case PACKAGE_OVERLAY_CONFIG_SIGNATURE: - return "Overlay Config Signature"; - case PACKAGE_RECENTS: - return "Recents"; - } - return "Unknown"; - } - - /** * Callback to listen for loading progress of a package installed on Incremental File System. */ public abstract static class InstalledLoadingProgressCallback { diff --git a/services/core/java/com/android/server/AlarmManagerInternal.java b/services/core/java/com/android/server/AlarmManagerInternal.java index e5ae77a26246..e3c8afabcf6f 100644 --- a/services/core/java/com/android/server/AlarmManagerInternal.java +++ b/services/core/java/com/android/server/AlarmManagerInternal.java @@ -44,7 +44,8 @@ public interface AlarmManagerInternal { /** * Returns if the given package in the given user holds - * {@link android.Manifest.permission#SCHEDULE_EXACT_ALARM} + * {@link android.Manifest.permission#SCHEDULE_EXACT_ALARM} or + * {@link android.Manifest.permission#USE_EXACT_ALARM}. */ - boolean hasScheduleExactAlarm(String packageName, int uid); + boolean hasExactAlarmPermission(String packageName, int uid); } diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java index 690051f47326..0cbc7ad404f5 100644 --- a/services/core/java/com/android/server/am/AppBatteryTracker.java +++ b/services/core/java/com/android/server/am/AppBatteryTracker.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION; import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET; import static android.app.ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED; import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET; +import static android.app.ActivityManager.RESTRICTION_LEVEL_UNKNOWN; import static android.app.ActivityManager.isLowRamDeviceStatic; import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM; import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; @@ -1119,6 +1120,13 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy> DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_high_threshold_by_bg_location"; /** + * Whether or not the battery usage of the offending app should fulfill the 1st threshold + * before taking actions for the 2nd threshold. + */ + static final String KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS = + DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_decouple_thresholds"; + + /** * Default value to the {@link #INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD} of * the {@link #mBgCurrentDrainRestrictedBucketThreshold}. */ @@ -1191,6 +1199,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy> final boolean mDefaultBgCurrentDrainHighThresholdByBgLocation; /** + * Default value to {@link #mBgCurrentDrainDecoupleThresholds}. + */ + static final boolean DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD = true; + + /** * The index to {@link #mBgCurrentDrainRestrictedBucketThreshold} * and {@link #mBgCurrentDrainBgRestrictedThreshold}. */ @@ -1258,6 +1271,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy> volatile boolean mBgCurrentDrainHighThresholdByBgLocation; /** + * @see #KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS. + */ + volatile boolean mBgCurrentDrainDecoupleThresholds; + + /** * The capacity of the battery when fully charged in mAh. */ private int mBatteryFullChargeMah; @@ -1369,6 +1387,9 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy> case KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES: updateCurrentDrainExemptedTypes(); break; + case KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS: + updateCurrentDrainDecoupleThresholds(); + break; default: super.onPropertiesChanged(name); break; @@ -1466,6 +1487,13 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy> mDefaultBgCurrentDrainExemptedTypes); } + private void updateCurrentDrainDecoupleThresholds() { + mBgCurrentDrainDecoupleThresholds = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS, + DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD); + } + @Override public void onSystemReady() { mBatteryFullChargeMah = @@ -1477,20 +1505,30 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy> updateCurrentDrainLocationMinDuration(); updateCurrentDrainEventDurationBasedThresholdEnabled(); updateCurrentDrainExemptedTypes(); + updateCurrentDrainDecoupleThresholds(); } @Override - public @RestrictionLevel int getProposedRestrictionLevel(String packageName, int uid) { + @RestrictionLevel + public int getProposedRestrictionLevel(String packageName, int uid, + @RestrictionLevel int maxLevel) { + if (maxLevel <= RESTRICTION_LEVEL_ADAPTIVE_BUCKET) { + return RESTRICTION_LEVEL_UNKNOWN; + } synchronized (mLock) { - final int index = mHighBgBatteryPackages.indexOfKey(uid); - if (index < 0) { - // Not found, return adaptive as the default one. - return RESTRICTION_LEVEL_ADAPTIVE_BUCKET; + final long[] ts = mHighBgBatteryPackages.get(uid); + if (ts != null) { + final int restrictedLevel = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] > 0 + ? RESTRICTION_LEVEL_RESTRICTED_BUCKET + : RESTRICTION_LEVEL_ADAPTIVE_BUCKET; + if (maxLevel > RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) { + return ts[TIME_STAMP_INDEX_BG_RESTRICTED] > 0 + ? RESTRICTION_LEVEL_BACKGROUND_RESTRICTED : restrictedLevel; + } else if (maxLevel == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) { + return restrictedLevel; + } } - final long[] ts = mHighBgBatteryPackages.valueAt(index); - return ts[TIME_STAMP_INDEX_BG_RESTRICTED] > 0 - ? RESTRICTION_LEVEL_BACKGROUND_RESTRICTED - : RESTRICTION_LEVEL_RESTRICTED_BUCKET; + return RESTRICTION_LEVEL_ADAPTIVE_BUCKET; } } @@ -1573,36 +1611,58 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy> final int thresholdIndex = getCurrentDrainThresholdIndex(uid, now, mBgCurrentDrainWindowMs); final int index = mHighBgBatteryPackages.indexOfKey(uid); + final boolean decoupleThresholds = mBgCurrentDrainDecoupleThresholds; + final double rbThreshold = mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex]; + final double brThreshold = mBgCurrentDrainBgRestrictedThreshold[thresholdIndex]; if (index < 0) { - if (rbPercentage >= mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex]) { + long[] ts = null; + if (rbPercentage >= rbThreshold) { // New findings to us, track it and let the controller know. - final long[] ts = new long[TIME_STAMP_INDEX_LAST]; + ts = new long[TIME_STAMP_INDEX_LAST]; ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now; mHighBgBatteryPackages.put(uid, ts); notifyController = excessive = true; } + if (decoupleThresholds && brPercentage >= brThreshold) { + if (ts == null) { + ts = new long[TIME_STAMP_INDEX_LAST]; + mHighBgBatteryPackages.put(uid, ts); + } + ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now; + notifyController = excessive = true; + } } else { final long[] ts = mHighBgBatteryPackages.valueAt(index); - if (rbPercentage < mBgCurrentDrainRestrictedBucketThreshold[thresholdIndex]) { - // it's actually back to normal, but we don't untrack it until - // explicit user interactions. - notifyController = true; + final long lastRestrictBucketTs = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET]; + if (rbPercentage >= rbThreshold) { + if (lastRestrictBucketTs == 0) { + ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now; + } + notifyController = excessive = true; } else { - excessive = true; - if (brPercentage >= mBgCurrentDrainBgRestrictedThreshold[thresholdIndex] - && curLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET) { - // If we're in the restricted standby bucket but still seeing high - // current drains, tell the controller again. - final long lastResbucket = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET]; - final long lastBgRes = ts[TIME_STAMP_INDEX_BG_RESTRICTED]; - // If it has been a while since restricting the app and since the last - // time we notify the controller, notify it again. - if ((now >= lastResbucket + mBgCurrentDrainWindowMs) && (lastBgRes == 0 - || (now >= lastBgRes + mBgCurrentDrainWindowMs))) { - ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now; - notifyController = true; - } + // It's actually back to normal, but we don't untrack it until + // explicit user interactions, because the restriction could be the cause + // of going back to normal. + } + if (brPercentage >= brThreshold) { + // If either + // a) It's configured to goto threshold 2 directly without threshold 1; + // b) It's already in the restricted standby bucket, but still seeing + // high current drains, and it's been a while since it's restricted; + // tell the controller. + notifyController = decoupleThresholds + || (curLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET + && (now > lastRestrictBucketTs + mBgCurrentDrainWindowMs)); + if (notifyController) { + ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now; } + excessive = true; + } else { + // Reset the track now - if it's already background restricted, it requires + // user consent to unrestrict it; or if it's in restricted bucket level, + // resetting this won't lift it from that level. + ts[TIME_STAMP_INDEX_BG_RESTRICTED] = 0; + // Now need to notify the controller. } } } diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java index 004760a302a7..6c183626fdad 100644 --- a/services/core/java/com/android/server/am/AppRestrictionController.java +++ b/services/core/java/com/android/server/am/AppRestrictionController.java @@ -24,6 +24,7 @@ import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET; import static android.app.ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED; import static android.app.ActivityManager.RESTRICTION_LEVEL_EXEMPTED; import static android.app.ActivityManager.RESTRICTION_LEVEL_HIBERNATION; +import static android.app.ActivityManager.RESTRICTION_LEVEL_MAX; import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET; import static android.app.ActivityManager.RESTRICTION_LEVEL_UNKNOWN; import static android.app.ActivityManager.UID_OBSERVER_ACTIVE; @@ -678,7 +679,7 @@ public final class AppRestrictionController { /** * Default value to {@link #mBgAbusiveNotificationMinIntervalMs}. */ - static final long DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS = ONE_DAY; + static final long DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS = 30 * ONE_DAY; /** * Default value to {@link #mBgAbusiveNotificationMinIntervalMs}. @@ -1152,7 +1153,8 @@ public final class AppRestrictionController { ? RESTRICTION_LEVEL_RESTRICTED_BUCKET : RESTRICTION_LEVEL_ADAPTIVE_BUCKET; if (calcTrackers) { - @RestrictionLevel int l = calcAppRestrictionLevelFromTackers(uid, packageName); + @RestrictionLevel int l = calcAppRestrictionLevelFromTackers(uid, packageName, + RESTRICTION_LEVEL_MAX); if (l == RESTRICTION_LEVEL_EXEMPTED) { return RESTRICTION_LEVEL_EXEMPTED; } @@ -1164,7 +1166,8 @@ public final class AppRestrictionController { uid, 0, packageName).sendToTarget(); } // Lower the level. - level = RESTRICTION_LEVEL_RESTRICTED_BUCKET; + level = calcAppRestrictionLevelFromTackers(uid, packageName, + RESTRICTION_LEVEL_BACKGROUND_RESTRICTED); } } break; @@ -1181,12 +1184,13 @@ public final class AppRestrictionController { * monitors certain dimensions of the app, the abusive behaviors could be detected in one or * more of these dimensions, but not necessarily all of them. </p> */ - private @RestrictionLevel int calcAppRestrictionLevelFromTackers(int uid, String packageName) { + private @RestrictionLevel int calcAppRestrictionLevelFromTackers(int uid, String packageName, + @RestrictionLevel int maxLevel) { @RestrictionLevel int level = RESTRICTION_LEVEL_UNKNOWN; final boolean isRestrictedBucketEnabled = mConstantsObserver.mRestrictedBucketEnabled; for (int i = mAppStateTrackers.size() - 1; i >= 0; i--) { @RestrictionLevel int l = mAppStateTrackers.get(i).getPolicy() - .getProposedRestrictionLevel(packageName, uid); + .getProposedRestrictionLevel(packageName, uid, maxLevel); if (!isRestrictedBucketEnabled && l == RESTRICTION_LEVEL_RESTRICTED_BUCKET) { l = RESTRICTION_LEVEL_ADAPTIVE_BUCKET; } @@ -1475,17 +1479,15 @@ public final class AppRestrictionController { } else if (curLevel >= RESTRICTION_LEVEL_RESTRICTED_BUCKET && level < RESTRICTION_LEVEL_RESTRICTED_BUCKET) { // Moved out of the background-restricted state. - if (curBucket != STANDBY_BUCKET_RARE) { - synchronized (mSettingsLock) { - final int index = mActiveUids.indexOfKey(uid, pkgName); - if (index >= 0) { - mActiveUids.add(uid, pkgName, null); - } + synchronized (mSettingsLock) { + final int index = mActiveUids.indexOfKey(uid, pkgName); + if (index >= 0) { + mActiveUids.add(uid, pkgName, null); } - appStandbyInternal.maybeUnrestrictApp(pkgName, UserHandle.getUserId(uid), - prevReason & REASON_MAIN_MASK, prevReason & REASON_SUB_MASK, - reason, subReason); } + appStandbyInternal.maybeUnrestrictApp(pkgName, UserHandle.getUserId(uid), + prevReason & REASON_MAIN_MASK, prevReason & REASON_SUB_MASK, + reason, subReason); } } diff --git a/services/core/java/com/android/server/am/BaseAppStatePolicy.java b/services/core/java/com/android/server/am/BaseAppStatePolicy.java index 67318a763907..a55344caea9a 100644 --- a/services/core/java/com/android/server/am/BaseAppStatePolicy.java +++ b/services/core/java/com/android/server/am/BaseAppStatePolicy.java @@ -87,9 +87,11 @@ public abstract class BaseAppStatePolicy<T extends BaseAppStateTracker> { } /** - * @return The proposed background restriction policy for the given package/uid. + * @return The proposed background restriction policy for the given package/uid, + * the returned level should be capped at {@code maxLevel} (exclusive). */ - public @RestrictionLevel int getProposedRestrictionLevel(String packageName, int uid) { + public @RestrictionLevel int getProposedRestrictionLevel(String packageName, int uid, + @RestrictionLevel int maxLevel) { return RESTRICTION_LEVEL_UNKNOWN; } diff --git a/services/core/java/com/android/server/am/BaseAppStateTimeSlotEventsTracker.java b/services/core/java/com/android/server/am/BaseAppStateTimeSlotEventsTracker.java index 2fbca1fa1724..b8aee13ccdd7 100644 --- a/services/core/java/com/android/server/am/BaseAppStateTimeSlotEventsTracker.java +++ b/services/core/java/com/android/server/am/BaseAppStateTimeSlotEventsTracker.java @@ -18,6 +18,7 @@ package com.android.server.am; import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET; import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET; +import static android.app.ActivityManager.RESTRICTION_LEVEL_UNKNOWN; import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM; import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE; @@ -295,11 +296,19 @@ abstract class BaseAppStateTimeSlotEventsTracker } @Override - public @RestrictionLevel int getProposedRestrictionLevel(String packageName, int uid) { + @RestrictionLevel + public int getProposedRestrictionLevel(String packageName, int uid, + @RestrictionLevel int maxLevel) { synchronized (mLock) { - return mExcessiveEventPkgs.get(packageName, uid) == null + final int level = mExcessiveEventPkgs.get(packageName, uid) == null ? RESTRICTION_LEVEL_ADAPTIVE_BUCKET : RESTRICTION_LEVEL_RESTRICTED_BUCKET; + if (maxLevel > RESTRICTION_LEVEL_RESTRICTED_BUCKET) { + return level; + } else if (maxLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET) { + return RESTRICTION_LEVEL_ADAPTIVE_BUCKET; + } + return RESTRICTION_LEVEL_UNKNOWN; } } diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java index 42a7423725a3..766283b92d91 100644 --- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java +++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java @@ -217,9 +217,13 @@ final class AmbientContextManagerPerUserService extends RemoteCallback detectionResultCallback, RemoteCallback statusCallback) { Slog.d(TAG, "Requested detection of " + request.getEventTypes()); synchronized (mLock) { - ensureRemoteServiceInitiated(); - mRemoteService.startDetection(request, callingPackage, detectionResultCallback, - statusCallback); + if (setUpServiceIfNeeded()) { + ensureRemoteServiceInitiated(); + mRemoteService.startDetection(request, callingPackage, detectionResultCallback, + statusCallback); + } else { + Slog.w(TAG, "No valid component found for AmbientContextDetectionService"); + } } } @@ -371,8 +375,10 @@ final class AmbientContextManagerPerUserService extends void stopDetection(String packageName) { Slog.d(TAG, "Stop detection for " + packageName); synchronized (mLock) { - ensureRemoteServiceInitiated(); - mRemoteService.stopDetection(packageName); + if (mComponentName != null) { + ensureRemoteServiceInitiated(); + mRemoteService.stopDetection(packageName); + } } } diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java index 2cdf7e7c7133..cfca7ec6f568 100644 --- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java +++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java @@ -42,6 +42,7 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.infra.AbstractMasterSystemService; import com.android.server.infra.FrameworkResourcesServiceNameResolver; +import com.android.server.pm.KnownPackages; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -117,7 +118,7 @@ public class AmbientContextManagerService extends public static boolean isDetectionServiceConfigured() { final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); final String[] packageNames = pmi.getKnownPackageNames( - PackageManagerInternal.PACKAGE_AMBIENT_CONTEXT_DETECTION, UserHandle.USER_SYSTEM); + KnownPackages.PACKAGE_AMBIENT_CONTEXT_DETECTION, UserHandle.USER_SYSTEM); boolean isServiceConfigured = (packageNames.length != 0); Slog.i(TAG, "Detection service configured: " + isServiceConfigured); return isServiceConfigured; @@ -249,6 +250,8 @@ public class AmbientContextManagerService extends Objects.requireNonNull(eventTypes); Objects.requireNonNull(callingPackage); assertCalledByPackageOwner(callingPackage); + mContext.enforceCallingOrSelfPermission( + Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG); mService.onStartConsentActivity(eventTypes, callingPackage); } diff --git a/services/core/java/com/android/server/biometrics/BiometricSensor.java b/services/core/java/com/android/server/biometrics/BiometricSensor.java index 7166783f0b23..937e3f8f8668 100644 --- a/services/core/java/com/android/server/biometrics/BiometricSensor.java +++ b/services/core/java/com/android/server/biometrics/BiometricSensor.java @@ -22,10 +22,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.content.Context; import android.hardware.biometrics.BiometricConstants; -import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.IBiometricSensorReceiver; -import android.hardware.biometrics.SensorPropertiesInternal; import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; @@ -149,7 +147,7 @@ public abstract class BiometricSensor { * Returns the actual strength, taking any updated strengths into effect. Since more bits * means lower strength, the resulting strength is never stronger than the OEM's configured * strength. - * @return a bitfield, see {@link BiometricManager.Authenticators} + * @return a bitfield, see {@link android.hardware.biometrics.BiometricManager.Authenticators} */ @Authenticators.Types int getCurrentStrength() { return oemStrength | mUpdatedStrength; @@ -169,27 +167,19 @@ public abstract class BiometricSensor { * @param newStrength */ void updateStrength(@Authenticators.Types int newStrength) { - String log = "updateStrength: Before(" + toString() + ")"; + String log = "updateStrength: Before(" + this + ")"; mUpdatedStrength = newStrength; - log += " After(" + toString() + ")"; + log += " After(" + this + ")"; Slog.d(TAG, log); } @Override public String toString() { - SensorPropertiesInternal properties = null; - try { - properties = impl.getSensorProperties(mContext.getOpPackageName()); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception", e); - } - return "ID(" + id + ")" + ", oemStrength: " + oemStrength + ", updatedStrength: " + mUpdatedStrength + ", modality " + modality + ", state: " + mSensorState - + ", cookie: " + mCookie - + ", props: " + properties; + + ", cookie: " + mCookie; } } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 82e1efd1b884..c88e3eb6d507 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -446,14 +446,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary adjustment set. private float mTemporaryAutoBrightnessAdjustment; - // Whether reduce bright colors (rbc) has been turned on, or a change in strength has been - // requested. We want to retain the current backlight level when rbc is toggled, since rbc - // additionally makes the screen appear dimmer using screen colors rather than backlight levels, - // and therefore we don't actually want to compensate for this by then in/decreasing the - // backlight when toggling this feature. - // This should be false during system start up. - private boolean mPendingRbcOnOrChanged = false; - // Animators. private ObjectAnimator mColorFadeOnAnimator; private ObjectAnimator mColorFadeOffAnimator; @@ -572,20 +564,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call @Override public void onReduceBrightColorsActivationChanged(boolean activated, boolean userInitiated) { - applyReduceBrightColorsSplineAdjustment( - /* rbcStrengthChanged= */ false, activated); + applyReduceBrightColorsSplineAdjustment(); } @Override public void onReduceBrightColorsStrengthChanged(int strength) { - applyReduceBrightColorsSplineAdjustment( - /* rbcStrengthChanged= */ true, /* justActivated= */ false); + applyReduceBrightColorsSplineAdjustment(); } }); if (active) { - applyReduceBrightColorsSplineAdjustment( - /* rbcStrengthChanged= */ false, /* justActivated= */ false); + applyReduceBrightColorsSplineAdjustment(); } } else { mCdsi = null; @@ -615,15 +604,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } - private void applyReduceBrightColorsSplineAdjustment( - boolean rbcStrengthChanged, boolean justActivated) { - final int strengthChanged = rbcStrengthChanged ? 1 : 0; - final int activated = justActivated ? 1 : 0; - mHandler.obtainMessage(MSG_UPDATE_RBC, strengthChanged, activated).sendToTarget(); + private void applyReduceBrightColorsSplineAdjustment() { + mHandler.obtainMessage(MSG_UPDATE_RBC).sendToTarget(); sendUpdatePowerState(); } - private void handleRbcChanged(boolean strengthChanged, boolean justActivated) { + private void handleRbcChanged() { if (mAutomaticBrightnessController == null) { return; } @@ -642,12 +628,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mAutomaticBrightnessController.recalculateSplines(mCdsi.isReduceBrightColorsActivated(), adjustedNits); - mPendingRbcOnOrChanged = strengthChanged || justActivated; - // Reset model if strength changed OR rbc is turned off - if ((strengthChanged || !justActivated) && mAutomaticBrightnessController != null) { - mAutomaticBrightnessController.resetShortTermModel(); - } + // If rbc is turned on, off or there is a change in strength, we want to reset the short + // term model. Since the nits range at which brightness now operates has changed due to + // RBC/strength change, any short term model based on the previous range should be + // invalidated. + mAutomaticBrightnessController.resetShortTermModel(); } /** @@ -1019,8 +1005,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private void reloadReduceBrightColours() { if (mCdsi != null && mCdsi.isReduceBrightColorsActivated()) { - applyReduceBrightColorsSplineAdjustment( - /* rbcStrengthChanged= */ false, /* justActivated= */ false); + applyReduceBrightColorsSplineAdjustment(); } } @@ -2285,23 +2270,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } // We want to return true if the user has set the screen brightness. - // If they have just turned RBC on (and therefore added that interaction to the curve), - // or changed the brightness another way, then we should return true. + // RBC on, off, and intensity changes will return false. + // Slider interactions whilst in RBC will return true, just as when in non-rbc. private boolean updateUserSetScreenBrightness() { - final boolean treatAsIfUserChanged = mPendingRbcOnOrChanged; - if (treatAsIfUserChanged && !Float.isNaN(mCurrentScreenBrightnessSetting)) { - mLastUserSetScreenBrightness = mCurrentScreenBrightnessSetting; - } - mPendingRbcOnOrChanged = false; - if ((Float.isNaN(mPendingScreenBrightnessSetting) || mPendingScreenBrightnessSetting < 0.0f)) { - return treatAsIfUserChanged; + return false; } if (mCurrentScreenBrightnessSetting == mPendingScreenBrightnessSetting) { mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT; mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; - return treatAsIfUserChanged; + return false; } setCurrentScreenBrightness(mPendingScreenBrightnessSetting); mLastUserSetScreenBrightness = mPendingScreenBrightnessSetting; @@ -2691,9 +2670,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call break; case MSG_UPDATE_RBC: - final int strengthChanged = msg.arg1; - final int justActivated = msg.arg2; - handleRbcChanged(strengthChanged == 1, justActivated == 1); + handleRbcChanged(); break; case MSG_BRIGHTNESS_RAMP_DONE: diff --git a/services/core/java/com/android/server/display/OWNERS b/services/core/java/com/android/server/display/OWNERS index 09d96be43a43..8e3460175158 100644 --- a/services/core/java/com/android/server/display/OWNERS +++ b/services/core/java/com/android/server/display/OWNERS @@ -3,5 +3,6 @@ dangittik@google.com hackbod@google.com ogunwale@google.com santoscordon@google.com +flc@google.com per-file ColorDisplayService.java=christyfranks@google.com diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 6cfaf9cce092..78cffa6f4f79 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -635,7 +635,7 @@ public class LockSettingsService extends ILockSettings.Stub { * If the account is credential-encrypted, show notification requesting the user to unlock the * device. */ - private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId) { + private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId, String reason) { final UserInfo user = mUserManager.getUserInfo(userId); if (!user.isManagedProfile()) { // When the user is locked, we communicate it loud-and-clear @@ -659,28 +659,35 @@ public class LockSettingsService extends ILockSettings.Stub { !mUserManager.isQuietModeEnabled(userHandle)) { // Only show notifications for managed profiles once their parent // user is unlocked. - showEncryptionNotificationForProfile(userHandle); + showEncryptionNotificationForProfile(userHandle, reason); } } } - private void showEncryptionNotificationForProfile(UserHandle user) { + private void showEncryptionNotificationForProfile(UserHandle user, String reason) { Resources r = mContext.getResources(); CharSequence title = getEncryptionNotificationTitle(); CharSequence message = getEncryptionNotificationMessage(); CharSequence detail = getEncryptionNotificationDetail(); final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE); - final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, - user.getIdentifier()); + final Intent unlockIntent = + km.createConfirmDeviceCredentialIntent(null, null, user.getIdentifier()); if (unlockIntent == null) { return; } + + // Suppress all notifications on non-FBE devices for now + if (!StorageManager.isFileEncryptedNativeOrEmulated()) return; + unlockIntent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED); + Slog.d(TAG, String.format("showing encryption notification, user: %d; reason: %s", + user.getIdentifier(), reason)); + showEncryptionNotification(user, title, message, detail, intent); } @@ -704,11 +711,6 @@ public class LockSettingsService extends ILockSettings.Stub { private void showEncryptionNotification(UserHandle user, CharSequence title, CharSequence message, CharSequence detail, PendingIntent intent) { - if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier()); - - // Suppress all notifications on non-FBE devices for now - if (!StorageManager.isFileEncryptedNativeOrEmulated()) return; - Notification notification = new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN) .setSmallIcon(com.android.internal.R.drawable.ic_user_secure) @@ -728,7 +730,7 @@ public class LockSettingsService extends ILockSettings.Stub { } private void hideEncryptionNotification(UserHandle userHandle) { - if (DEBUG) Slog.v(TAG, "hide encryption notification, user: " + userHandle.getIdentifier()); + Slog.d(TAG, "hide encryption notification, user: " + userHandle.getIdentifier()); mNotificationManager.cancelAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION, userHandle); } @@ -746,7 +748,7 @@ public class LockSettingsService extends ILockSettings.Stub { } public void onStartUser(final int userId) { - maybeShowEncryptionNotificationForUser(userId); + maybeShowEncryptionNotificationForUser(userId, "user started"); } /** @@ -1497,7 +1499,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (!alreadyUnlocked) { final long ident = clearCallingIdentity(); try { - maybeShowEncryptionNotificationForUser(profile.id); + maybeShowEncryptionNotificationForUser(profile.id, "parent unlocked"); } finally { restoreCallingIdentity(ident); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index a284ada11a49..a04204d90302 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -5030,8 +5030,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) { postBlockedReasonsChangedMsg(uid, - oldEffectiveBlockedReasons, - newEffectiveBlockedReasons); + newEffectiveBlockedReasons, + oldEffectiveBlockedReasons); postUidRulesChangedMsg(uid, uidRules); } diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index ee0b3d52eb3d..8ecc607603a1 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -82,6 +82,7 @@ import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.SystemConfig; import com.android.server.SystemService; +import com.android.server.pm.KnownPackages; import com.android.server.pm.UserManagerService; import com.android.server.pm.parsing.pkg.AndroidPackage; @@ -1264,7 +1265,7 @@ public final class OverlayManagerService extends SystemService { @Override public String getConfigSignaturePackage() { final String[] pkgs = mPackageManagerInternal.getKnownPackageNames( - PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE, + KnownPackages.PACKAGE_OVERLAY_CONFIG_SIGNATURE, UserHandle.USER_SYSTEM); return (pkgs.length == 0) ? null : pkgs[0]; } diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java index 8e853019de90..3e204b6e6e4c 100644 --- a/services/core/java/com/android/server/pm/Computer.java +++ b/services/core/java/com/android/server/pm/Computer.java @@ -45,6 +45,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Pair; import android.util.SparseArray; +import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.server.pm.parsing.pkg.AndroidPackage; @@ -571,6 +572,31 @@ public interface Computer extends PackageDataSnapshot { @NonNull WatchedArrayMap<String, Integer> getFrozenPackages(); + /** + * Verify that given package is currently frozen. + */ + void checkPackageFrozen(@NonNull String packageName); + @Nullable ComponentName getInstantAppInstallerComponent(); + + void dumpPermissions(@NonNull PrintWriter pw, @NonNull String packageName, + @NonNull ArraySet<String> permissionNames, @NonNull DumpState dumpState); + + void dumpPackages(PrintWriter pw, @NonNull String packageName, + @NonNull ArraySet<String> permissionNames, @NonNull DumpState dumpState, + boolean checkin); + + void dumpKeySet(@NonNull PrintWriter pw, @NonNull String packageName, + @NonNull DumpState dumpState); + + void dumpSharedUsers(@NonNull PrintWriter pw, @NonNull String packageName, + @NonNull ArraySet<String> permissionNames, + @NonNull DumpState dumpState, boolean checkin); + + void dumpSharedUsersProto(@NonNull ProtoOutputStream proto); + + void dumpPackagesProto(@NonNull ProtoOutputStream proto); + + void dumpSharedLibrariesProto(@NonNull ProtoOutputStream protoOutputStream); } diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index 4abfd3404295..8432f48e269e 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -117,6 +117,7 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.TypedXmlSerializer; import android.util.Xml; +import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; @@ -322,6 +323,37 @@ public class ComputerEngine implements Computer { } return res; } + + public void dumpPackagesProto(ProtoOutputStream proto) { + mSettings.dumpPackagesProto(proto); + } + + public void dumpPermissions(PrintWriter pw, String packageName, + ArraySet<String> permissionNames, DumpState dumpState) { + mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState); + } + + public void dumpPackages(PrintWriter pw, String packageName, + ArraySet<String> permissionNames, DumpState dumpState, boolean checkin) { + mSettings.dumpPackagesLPr(pw, packageName, permissionNames, dumpState, checkin); + } + + public void dumpKeySet(PrintWriter pw, String packageName, DumpState dumpState) { + mSettings.getKeySetManagerService().dumpLPr(pw, packageName, dumpState); + } + + public void dumpSharedUsers(PrintWriter pw, String packageName, + ArraySet<String> permissionNames, DumpState dumpState, boolean checkin) { + mSettings.dumpSharedUsersLPr(pw, packageName, permissionNames, dumpState, checkin); + } + + public void dumpReadMessages(PrintWriter pw, DumpState dumpState) { + mSettings.dumpReadMessages(pw, dumpState); + } + + public void dumpSharedUsersProto(ProtoOutputStream proto) { + mSettings.dumpSharedUsersProto(proto); + } } private static final Comparator<ProviderInfo> sProviderInitOrderSorter = (p1, p2) -> { @@ -3211,6 +3243,34 @@ public class ComputerEngine implements Computer { } break; } + + case DumpState.DUMP_MESSAGES: { + mSettings.dumpReadMessages(pw, dumpState); + break; + } + + case DumpState.DUMP_FROZEN: { + // XXX should handle packageName != null by dumping only install data that + // the given package is involved with. + if (dumpState.onTitlePrinted()) { + pw.println(); + } + final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); + ipw.println(); + ipw.println("Frozen packages:"); + ipw.increaseIndent(); + if (mFrozenPackages.size() == 0) { + ipw.println("(none)"); + } else { + for (int i = 0; i < mFrozenPackages.size(); i++) { + ipw.print("package="); + ipw.print(mFrozenPackages.keyAt(i)); + ipw.print(", refCounts="); + ipw.println(mFrozenPackages.valueAt(i)); + } + } + ipw.decreaseIndent(); + } } // switch } @@ -5698,10 +5758,58 @@ public class ComputerEngine implements Computer { return mFrozenPackages; } + @Override + public void checkPackageFrozen(@NonNull String packageName) { + if (!mFrozenPackages.containsKey(packageName)) { + Slog.wtf(TAG, "Expected " + packageName + " to be frozen!", new Throwable()); + } + } + @Nullable @Override public ComponentName getInstantAppInstallerComponent() { return mLocalInstantAppInstallerActivity == null ? null : mLocalInstantAppInstallerActivity.getComponentName(); } + + @Override + public void dumpPermissions(@NonNull PrintWriter pw, @NonNull String packageName, + @NonNull ArraySet<String> permissionNames, @NonNull DumpState dumpState) { + mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState); + } + + @Override + public void dumpPackages(@NonNull PrintWriter pw, @NonNull String packageName, + @NonNull ArraySet<String> permissionNames, @NonNull DumpState dumpState, + boolean checkin) { + mSettings.dumpPackages(pw, packageName, permissionNames, dumpState, checkin); + } + + @Override + public void dumpKeySet(@NonNull PrintWriter pw, @NonNull String packageName, + @NonNull DumpState dumpState) { + mSettings.dumpKeySet(pw, packageName, dumpState); + } + + @Override + public void dumpSharedUsers(@NonNull PrintWriter pw, @NonNull String packageName, + @NonNull ArraySet<String> permissionNames, @NonNull DumpState dumpState, + boolean checkin) { + mSettings.dumpSharedUsers(pw, packageName, permissionNames, dumpState, checkin); + } + + @Override + public void dumpSharedUsersProto(@NonNull ProtoOutputStream proto) { + mSettings.dumpSharedUsersProto(proto); + } + + @Override + public void dumpPackagesProto(@NonNull ProtoOutputStream proto) { + mSettings.dumpPackagesProto(proto); + } + + @Override + public void dumpSharedLibrariesProto(@NonNull ProtoOutputStream proto) { + mSharedLibraries.dumpProto(proto); + } } diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java index dc4dd12b3a18..7dae22a44cc5 100644 --- a/services/core/java/com/android/server/pm/DeletePackageHelper.java +++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java @@ -167,6 +167,7 @@ final class DeletePackageHelper { if (userInfo == null || !userInfo.isAdmin()) { Slog.w(TAG, "Not removing package " + packageName + " as only admin user may downgrade system apps"); + EventLog.writeEvent(0x534e4554, "170646036", -1, packageName); return PackageManager.DELETE_FAILED_USER_RESTRICTED; } } diff --git a/services/core/java/com/android/server/pm/DumpHelper.java b/services/core/java/com/android/server/pm/DumpHelper.java index f83ef5aea23a..276644036def 100644 --- a/services/core/java/com/android/server/pm/DumpHelper.java +++ b/services/core/java/com/android/server/pm/DumpHelper.java @@ -17,45 +17,76 @@ package com.android.server.pm; import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; -import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE; +import static com.android.server.pm.KnownPackages.LAST_KNOWN_PACKAGE; import static com.android.server.pm.PackageManagerServiceUtils.dumpCriticalInfo; +import android.annotation.NonNull; import android.content.ComponentName; import android.content.pm.FeatureInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManagerInternal; import android.os.Binder; import android.os.UserHandle; import android.os.incremental.PerUidReadTimeouts; import android.service.pm.PackageServiceDumpProto; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; +import com.android.server.pm.permission.PermissionManagerServiceInternal; +import com.android.server.pm.resolution.ComponentResolverApi; +import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy; import dalvik.annotation.optimization.NeverCompile; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.function.BiConsumer; /** * Dumps PackageManagerService internal states. */ final class DumpHelper { - final PackageManagerService mPm; - - DumpHelper(PackageManagerService pm) { - mPm = pm; + private final PermissionManagerServiceInternal mPermissionManager; + private final ApexManager mApexManager; + private final StorageEventHelper mStorageEventHelper; + private final DomainVerificationManagerInternal mDomainVerificationManager; + private final PackageInstallerService mInstallerService; + private final String mRequiredVerifierPackage; + private final KnownPackages mKnownPackages; + private final ChangedPackagesTracker mChangedPackagesTracker; + private final ArrayMap<String, FeatureInfo> mAvailableFeatures; + private final ArraySet<String> mProtectedBroadcasts; + private final PerUidReadTimeouts[] mPerUidReadTimeouts; + + DumpHelper( + PermissionManagerServiceInternal permissionManager, ApexManager apexManager, + StorageEventHelper storageEventHelper, + DomainVerificationManagerInternal domainVerificationManager, + PackageInstallerService installerService, String requiredVerifierPackage, + KnownPackages knownPackages, + ChangedPackagesTracker changedPackagesTracker, + ArrayMap<String, FeatureInfo> availableFeatures, + ArraySet<String> protectedBroadcasts, + PerUidReadTimeouts[] perUidReadTimeouts) { + mPermissionManager = permissionManager; + mApexManager = apexManager; + mStorageEventHelper = storageEventHelper; + mDomainVerificationManager = domainVerificationManager; + mInstallerService = installerService; + mRequiredVerifierPackage = requiredVerifierPackage; + mKnownPackages = knownPackages; + mChangedPackagesTracker = changedPackagesTracker; + mAvailableFeatures = availableFeatures; + mProtectedBroadcasts = protectedBroadcasts; + mPerUidReadTimeouts = perUidReadTimeouts; } @NeverCompile // Avoid size overhead of debugging code. - public void doDump(FileDescriptor fd, PrintWriter pw, String[] args) { - final Computer snapshot = mPm.snapshotComputer(); + public void doDump(Computer snapshot, FileDescriptor fd, PrintWriter pw, String[] args) { DumpState dumpState = new DumpState(); ArraySet<String> permissionNames = null; @@ -79,7 +110,7 @@ final class DumpHelper { } else if ("-f".equals(opt)) { dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS); } else if ("--proto".equals(opt)) { - dumpProto(fd); + dumpProto(snapshot, fd); return; } else { pw.println("Unknown argument: " + opt + "; use -h for help"); @@ -122,9 +153,10 @@ final class DumpHelper { } // Normalize package name to handle renamed packages and static libs - pkg = snapshot.resolveInternalPackageName(pkg, PackageManager.VERSION_CODE_HIGHEST); + pkg = snapshot.resolveInternalPackageName(pkg, + PackageManager.VERSION_CODE_HIGHEST); - pw.println(mPm.checkPermission(perm, pkg, user)); + pw.println(mPermissionManager.checkPermission(perm, pkg, user)); return; } else if ("l".equals(cmd) || "libraries".equals(cmd)) { dumpState.setDump(DumpState.DUMP_LIBS); @@ -230,12 +262,6 @@ final class DumpHelper { } } else if ("protected-broadcasts".equals(cmd)) { dumpState.setDump(DumpState.DUMP_PROTECTED_BROADCASTS); - } else if ("write".equals(cmd)) { - synchronized (mPm.mLock) { - mPm.writeSettingsLPrTEMP(); - pw.println("Settings written."); - return; - } } } @@ -245,7 +271,7 @@ final class DumpHelper { // Return if the package doesn't exist. if (packageName != null && snapshot.getPackageStateInternal(packageName) == null - && !mPm.mApexManager.isApexPackage(packageName)) { + && !mApexManager.isApexPackage(packageName)) { pw.println("Unable to find package: " + packageName); return; } @@ -271,11 +297,11 @@ final class DumpHelper { ipw.println("Known Packages:"); ipw.increaseIndent(); for (int i = 0; i <= LAST_KNOWN_PACKAGE; i++) { - final String knownPackage = PackageManagerInternal.knownPackageToString(i); + final String knownPackage = KnownPackages.knownPackageToString(i); ipw.print(knownPackage); ipw.println(":"); - final String[] pkgNames = mPm.getKnownPackageNamesInternal(snapshot, i, - UserHandle.USER_SYSTEM); + final String[] pkgNames = mKnownPackages.getKnownPackageNames(snapshot, + i, UserHandle.USER_SYSTEM); ipw.increaseIndent(); if (ArrayUtils.isEmpty(pkgNames)) { ipw.println("none"); @@ -291,7 +317,7 @@ final class DumpHelper { if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) { - final String requiredVerifierPackage = mPm.mRequiredVerifierPackage; + final String requiredVerifierPackage = mRequiredVerifierPackage; if (!checkin) { if (dumpState.onTitlePrinted()) { pw.println(); @@ -304,7 +330,8 @@ final class DumpHelper { MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM)); pw.println(")"); } else if (requiredVerifierPackage != null) { - pw.print("vrfy,"); pw.print(requiredVerifierPackage); + pw.print("vrfy,"); + pw.print(requiredVerifierPackage); pw.print(","); pw.println(snapshot.getPackageUid(requiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM)); @@ -313,7 +340,7 @@ final class DumpHelper { if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER) && packageName == null) { - final DomainVerificationProxy proxy = mPm.mDomainVerificationManager.getProxy(); + final DomainVerificationProxy proxy = mDomainVerificationManager.getProxy(); final ComponentName verifierComponent = proxy.getComponentName(); if (verifierComponent != null) { String verifierPackageName = verifierComponent.getPackageName(); @@ -329,7 +356,8 @@ final class DumpHelper { MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM)); pw.println(")"); } else if (verifierPackageName != null) { - pw.print("dv,"); pw.print(verifierPackageName); + pw.print("dv,"); + pw.print(verifierPackageName); pw.print(","); pw.println(snapshot.getPackageUid(verifierPackageName, MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM)); @@ -354,76 +382,75 @@ final class DumpHelper { pw.println("Features:"); } - synchronized (mPm.mAvailableFeatures) { - for (FeatureInfo feat : mPm.mAvailableFeatures.values()) { - if (!checkin) { - pw.print(" "); - pw.print(feat.name); - if (feat.version > 0) { - pw.print(" version="); - pw.print(feat.version); - } - pw.println(); - } else { - pw.print("feat,"); - pw.print(feat.name); - pw.print(","); - pw.println(feat.version); + for (FeatureInfo feat : mAvailableFeatures.values()) { + if (!checkin) { + pw.print(" "); + pw.print(feat.name); + if (feat.version > 0) { + pw.print(" version="); + pw.print(feat.version); } + pw.println(); + } else { + pw.print("feat,"); + pw.print(feat.name); + pw.print(","); + pw.println(feat.version); } } } - if (!checkin && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) { - mPm.mComponentResolver.dumpActivityResolvers(pw, dumpState, packageName); + final ComponentResolverApi componentResolver = snapshot.getComponentResolver(); + if (!checkin + && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) { + componentResolver.dumpActivityResolvers(pw, dumpState, packageName); } - if (!checkin && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) { - mPm.mComponentResolver.dumpReceiverResolvers(pw, dumpState, packageName); + if (!checkin + && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) { + componentResolver.dumpReceiverResolvers(pw, dumpState, packageName); } - if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) { - mPm.mComponentResolver.dumpServiceResolvers(pw, dumpState, packageName); + if (!checkin + && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) { + componentResolver.dumpServiceResolvers(pw, dumpState, packageName); } - if (!checkin && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) { - mPm.mComponentResolver.dumpProviderResolvers(pw, dumpState, packageName); + if (!checkin + && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) { + componentResolver.dumpProviderResolvers(pw, dumpState, packageName); } - if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) { + if (!checkin + && dumpState.isDumping(DumpState.DUMP_PREFERRED)) { snapshot.dump(DumpState.DUMP_PREFERRED, fd, pw, dumpState); } if (!checkin - && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML) - && packageName == null) { + && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML) && packageName == null) { snapshot.dump(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState); } - if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) { + if (!checkin + && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) { snapshot.dump(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState); } - if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) { - mPm.mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState); + if (!checkin + && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) { + snapshot.dumpPermissions(pw, packageName, permissionNames, dumpState); } - if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) { - mPm.mComponentResolver.dumpContentProviders(snapshot, pw, dumpState, + if (!checkin + && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) { + componentResolver.dumpContentProviders(snapshot, pw, dumpState, packageName); } if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) { - synchronized (mPm.mLock) { - mPm.mSettings.getKeySetManagerService().dumpLPr(pw, packageName, dumpState); - } + snapshot.dumpKeySet(pw, packageName, dumpState); } if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) { - // This cannot be moved to ComputerEngine since some variables of the collections - // in PackageUserState such as suspendParams, disabledComponents and enabledComponents - // do not have a copy. - synchronized (mPm.mLock) { - mPm.mSettings.dumpPackagesLPr(pw, packageName, permissionNames, dumpState, checkin); - } + snapshot.dumpPackages(pw, packageName, permissionNames, dumpState, checkin); } if (!checkin @@ -432,12 +459,8 @@ final class DumpHelper { } if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) { - // This cannot be moved to ComputerEngine since the set of packages in the - // SharedUserSetting do not have a copy. - synchronized (mPm.mLock) { - mPm.mSettings.dumpSharedUsersLPr(pw, packageName, permissionNames, dumpState, - checkin); - } + snapshot.dumpSharedUsers(pw, packageName, permissionNames, dumpState, + checkin); } if (!checkin @@ -447,15 +470,19 @@ final class DumpHelper { pw.println(); } pw.println("Package Changes:"); - mPm.mChangedPackagesTracker.iterateAll((sequenceNumber, values) -> { - pw.print(" Sequence number="); pw.println(sequenceNumber); + mChangedPackagesTracker.iterateAll((sequenceNumber, values) -> { + pw.print(" Sequence number="); + pw.println(sequenceNumber); final int numChangedPackages = values.size(); for (int i = 0; i < numChangedPackages; i++) { final SparseArray<String> changes = values.valueAt(i); - pw.print(" User "); pw.print(values.keyAt(i)); pw.println(":"); + pw.print(" User "); + pw.print(values.keyAt(i)); + pw.println(":"); final int numChanges = changes.size(); if (numChanges == 0) { - pw.print(" "); pw.println("No packages changed"); + pw.print(" "); + pw.println("No packages changed"); } else { for (int j = 0; j < numChanges; j++) { final String pkgName = changes.valueAt(j); @@ -474,56 +501,19 @@ final class DumpHelper { if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) { - // XXX should handle packageName != null by dumping only install data that - // the given package is involved with. - if (dumpState.onTitlePrinted()) { - pw.println(); - } - final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); - ipw.println(); - ipw.println("Frozen packages:"); - ipw.increaseIndent(); - synchronized (mPm.mLock) { - if (mPm.mFrozenPackages.size() == 0) { - ipw.println("(none)"); - } else { - for (int i = 0; i < mPm.mFrozenPackages.size(); i++) { - ipw.print("package="); - ipw.print(mPm.mFrozenPackages.keyAt(i)); - ipw.print(", refCounts="); - ipw.println(mPm.mFrozenPackages.valueAt(i)); - } - } - } - ipw.decreaseIndent(); + snapshot.dump(DumpState.DUMP_FROZEN, fd, pw, dumpState); } if (!checkin && dumpState.isDumping(DumpState.DUMP_VOLUMES) && packageName == null) { - if (dumpState.onTitlePrinted()) { - pw.println(); - } - final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); - ipw.println(); - ipw.println("Loaded volumes:"); - ipw.increaseIndent(); - synchronized (mPm.mLoadedVolumes) { - if (mPm.mLoadedVolumes.size() == 0) { - ipw.println("(none)"); - } else { - for (int i = 0; i < mPm.mLoadedVolumes.size(); i++) { - ipw.println(mPm.mLoadedVolumes.valueAt(i)); - } - } - } - ipw.decreaseIndent(); + mStorageEventHelper.dumpLoadedVolumes(pw, dumpState); } if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS) && packageName == null) { - mPm.mComponentResolver.dumpServicePermissions(pw, dumpState); + componentResolver.dumpServicePermissions(pw, dumpState); } if (!checkin @@ -542,7 +532,7 @@ final class DumpHelper { if (dumpState.onTitlePrinted()) { pw.println(); } - mPm.mSettings.dumpReadMessages(pw, dumpState); + snapshot.dump(DumpState.DUMP_MESSAGES, fd, pw, dumpState); pw.println(); pw.println("Package warning messages:"); dumpCriticalInfo(pw, null); @@ -560,13 +550,13 @@ final class DumpHelper { if (dumpState.onTitlePrinted()) { pw.println(); } - mPm.mInstallerService.dump(new IndentingPrintWriter(pw, " ", 120)); + mInstallerService.dump(new IndentingPrintWriter(pw, " ", 120)); } if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX) - && (packageName == null || mPm.mApexManager.isApexPackage(packageName))) { - mPm.mApexManager.dump(pw, packageName); + && (packageName == null || mApexManager.isApexPackage(packageName))) { + mApexManager.dump(pw, packageName); } if (!checkin @@ -580,9 +570,8 @@ final class DumpHelper { pw.println(" Known digesters list flag: " + PackageManagerService.getKnownDigestersList()); - PerUidReadTimeouts[] items = mPm.getPerUidReadTimeouts(snapshot); - pw.println(" Timeouts (" + items.length + "):"); - for (PerUidReadTimeouts item : items) { + pw.println(" Timeouts (" + mPerUidReadTimeouts.length + "):"); + for (PerUidReadTimeouts item : mPerUidReadTimeouts) { pw.print(" ("); pw.print("uid=" + item.uid + ", "); pw.print("minTimeUs=" + item.minTimeUs + ", "); @@ -598,8 +587,6 @@ final class DumpHelper { if (dumpState.onTitlePrinted()) { pw.println(); } - pw.println("Snapshot statistics"); - mPm.dumpSnapshotStats(pw, dumpState.isBrief()); } if (!checkin @@ -609,11 +596,9 @@ final class DumpHelper { pw.println(); } pw.println("Protected broadcast actions:"); - synchronized (mPm.mProtectedBroadcasts) { - for (int i = 0; i < mPm.mProtectedBroadcasts.size(); i++) { - pw.print(" "); - pw.println(mPm.mProtectedBroadcasts.valueAt(i)); - } + for (int i = 0; i < mProtectedBroadcasts.size(); i++) { + pw.print(" "); + pw.println(mProtectedBroadcasts.valueAt(i)); } } @@ -658,55 +643,50 @@ final class DumpHelper { pw.println(" <package.name>: info about given package"); } - private void dumpProto(FileDescriptor fd) { + private void dumpProto(Computer snapshot, FileDescriptor fd) { final ProtoOutputStream proto = new ProtoOutputStream(fd); - synchronized (mPm.mLock) { - final Computer snapshot = mPm.snapshotComputer(); - final long requiredVerifierPackageToken = - proto.start(PackageServiceDumpProto.REQUIRED_VERIFIER_PACKAGE); - proto.write(PackageServiceDumpProto.PackageShortProto.NAME, - mPm.mRequiredVerifierPackage); + final long requiredVerifierPackageToken = + proto.start(PackageServiceDumpProto.REQUIRED_VERIFIER_PACKAGE); + proto.write(PackageServiceDumpProto.PackageShortProto.NAME, + mRequiredVerifierPackage); + proto.write( + PackageServiceDumpProto.PackageShortProto.UID, + snapshot.getPackageUid( + mRequiredVerifierPackage, + MATCH_DEBUG_TRIAGED_MISSING, + UserHandle.USER_SYSTEM)); + proto.end(requiredVerifierPackageToken); + + DomainVerificationProxy proxy = mDomainVerificationManager.getProxy(); + ComponentName verifierComponent = proxy.getComponentName(); + if (verifierComponent != null) { + String verifierPackageName = verifierComponent.getPackageName(); + final long verifierPackageToken = + proto.start(PackageServiceDumpProto.VERIFIER_PACKAGE); + proto.write(PackageServiceDumpProto.PackageShortProto.NAME, verifierPackageName); proto.write( PackageServiceDumpProto.PackageShortProto.UID, snapshot.getPackageUid( - mPm.mRequiredVerifierPackage, + verifierPackageName, MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM)); - proto.end(requiredVerifierPackageToken); - - DomainVerificationProxy proxy = mPm.mDomainVerificationManager.getProxy(); - ComponentName verifierComponent = proxy.getComponentName(); - if (verifierComponent != null) { - String verifierPackageName = verifierComponent.getPackageName(); - final long verifierPackageToken = - proto.start(PackageServiceDumpProto.VERIFIER_PACKAGE); - proto.write(PackageServiceDumpProto.PackageShortProto.NAME, verifierPackageName); - proto.write( - PackageServiceDumpProto.PackageShortProto.UID, - snapshot.getPackageUid( - verifierPackageName, - MATCH_DEBUG_TRIAGED_MISSING, - UserHandle.USER_SYSTEM)); - proto.end(verifierPackageToken); - } - - mPm.mInjector.getSharedLibrariesImpl().dumpProto(proto); - dumpFeaturesProto(proto); - mPm.mSettings.dumpPackagesProto(proto); - mPm.mSettings.dumpSharedUsersProto(proto); - dumpCriticalInfo(proto); + proto.end(verifierPackageToken); } + + snapshot.dumpSharedLibrariesProto(proto); + dumpAvailableFeaturesProto(proto); + snapshot.dumpPackagesProto(proto); + snapshot.dumpSharedUsersProto(proto); + dumpCriticalInfo(proto); proto.flush(); } - private void dumpFeaturesProto(ProtoOutputStream proto) { - synchronized (mPm.mAvailableFeatures) { - final int count = mPm.mAvailableFeatures.size(); - for (int i = 0; i < count; i++) { - mPm.mAvailableFeatures.valueAt(i).dumpDebug(proto, - PackageServiceDumpProto.FEATURES); - } + + private void dumpAvailableFeaturesProto(@NonNull ProtoOutputStream proto) { + final int count = mAvailableFeatures.size(); + for (int i = 0; i < count; i++) { + mAvailableFeatures.valueAt(i).dumpDebug(proto, PackageServiceDumpProto.FEATURES); } } } diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java index e1aee6d747f4..ba7309f0283d 100644 --- a/services/core/java/com/android/server/pm/IPackageManagerBase.java +++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java @@ -803,7 +803,7 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { public final String getSystemCaptionsServicePackageName() { return mService.ensureSystemPackageName(snapshot(), mService.getPackageFromComponentString( - R.string.config_defaultSystemCaptionsService)); + R.string.config_defaultSystemCaptionsManagerService)); } @Nullable diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 870a11ac2d61..77d37dc377a2 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -427,7 +427,7 @@ final class InstallPackageHelper { } else { // We're doing major surgery on this package, so it better be frozen // right now to keep it from launching - mPm.checkPackageFrozen(pkgName); + mPm.snapshotComputer().checkPackageFrozen(pkgName); } final boolean isReplace = diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 5fadd00b77ad..2a66e026438a 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -692,6 +692,20 @@ public class Installer extends SystemService { } } + /** + * Deletes the reference profile with the given name of the given package. + * @throws InstallerException if the deletion fails. + */ + public void deleteReferenceProfile(String packageName, String profileName) + throws InstallerException { + if (!checkBeforeRemote()) return; + try { + mInstalld.deleteReferenceProfile(packageName, profileName); + } catch (Exception e) { + throw InstallerException.from(e); + } + } + public void createUserData(String uuid, int userId, int userSerial, int flags) throws InstallerException { if (!checkBeforeRemote()) return; diff --git a/services/core/java/com/android/server/pm/IntentResolverInterceptor.java b/services/core/java/com/android/server/pm/IntentResolverInterceptor.java index 5597c9af7362..603badb276b2 100644 --- a/services/core/java/com/android/server/pm/IntentResolverInterceptor.java +++ b/services/core/java/com/android/server/pm/IntentResolverInterceptor.java @@ -81,7 +81,7 @@ public final class IntentResolverInterceptor { private void updateUseDelegateChooser() { mUseDelegateChooser = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.USE_DELEGATE_CHOOSER, + SystemUiDeviceConfigFlags.USE_UNBUNDLED_SHARESHEET, false); } diff --git a/services/core/java/com/android/server/pm/KnownPackages.java b/services/core/java/com/android/server/pm/KnownPackages.java new file mode 100644 index 000000000000..04376b448e32 --- /dev/null +++ b/services/core/java/com/android/server/pm/KnownPackages.java @@ -0,0 +1,213 @@ +/* + * 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.pm; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.text.TextUtils; + +import com.android.internal.util.ArrayUtils; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Helps {@link PackageManagerService} keep track of the names of special packages like SetupWizard. + */ +public final class KnownPackages { + @IntDef(prefix = "PACKAGE_", value = { + PACKAGE_SYSTEM, + PACKAGE_SETUP_WIZARD, + PACKAGE_INSTALLER, + PACKAGE_UNINSTALLER, + PACKAGE_VERIFIER, + PACKAGE_BROWSER, + PACKAGE_SYSTEM_TEXT_CLASSIFIER, + PACKAGE_PERMISSION_CONTROLLER, + PACKAGE_CONFIGURATOR, + PACKAGE_INCIDENT_REPORT_APPROVER, + PACKAGE_APP_PREDICTOR, + PACKAGE_OVERLAY_CONFIG_SIGNATURE, + PACKAGE_WIFI, + PACKAGE_COMPANION, + PACKAGE_RETAIL_DEMO, + PACKAGE_RECENTS, + PACKAGE_AMBIENT_CONTEXT_DETECTION, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface KnownPackage { + } + + public static final int PACKAGE_SYSTEM = 0; + public static final int PACKAGE_SETUP_WIZARD = 1; + public static final int PACKAGE_INSTALLER = 2; + public static final int PACKAGE_UNINSTALLER = 3; + public static final int PACKAGE_VERIFIER = 4; + public static final int PACKAGE_BROWSER = 5; + public static final int PACKAGE_SYSTEM_TEXT_CLASSIFIER = 6; + public static final int PACKAGE_PERMISSION_CONTROLLER = 7; + public static final int PACKAGE_WELLBEING = 8; + public static final int PACKAGE_DOCUMENTER = 9; + public static final int PACKAGE_CONFIGURATOR = 10; + public static final int PACKAGE_INCIDENT_REPORT_APPROVER = 11; + public static final int PACKAGE_APP_PREDICTOR = 12; + public static final int PACKAGE_OVERLAY_CONFIG_SIGNATURE = 13; + public static final int PACKAGE_WIFI = 14; + public static final int PACKAGE_COMPANION = 15; + public static final int PACKAGE_RETAIL_DEMO = 16; + public static final int PACKAGE_RECENTS = 17; + public static final int PACKAGE_AMBIENT_CONTEXT_DETECTION = 18; + // Integer value of the last known package ID. Increases as new ID is added to KnownPackage. + // Please note the numbers should be continuous. + public static final int LAST_KNOWN_PACKAGE = PACKAGE_AMBIENT_CONTEXT_DETECTION; + + private final DefaultAppProvider mDefaultAppProvider; + private final String mRequiredInstallerPackage; + private final String mRequiredUninstallerPackage; + private final String mSetupWizardPackage; + private final String mRequiredVerifierPackage; + private final String mDefaultTextClassifierPackage; + private final String mSystemTextClassifierPackageName; + private final String mRequiredPermissionControllerPackage; + private final String mConfiguratorPackage; + private final String mIncidentReportApproverPackage; + private final String mAmbientContextDetectionPackage; + private final String mAppPredictionServicePackage; + private final String mCompanionPackage; + private final String mRetailDemoPackage; + private final String mOverlayConfigSignaturePackage; + private final String mRecentsPackage; + + KnownPackages(DefaultAppProvider defaultAppProvider, String requiredInstallerPackage, + String requiredUninstallerPackage, String setupWizardPackage, + String requiredVerifierPackage, String defaultTextClassifierPackage, + String systemTextClassifierPackageName, String requiredPermissionControllerPackage, + String configuratorPackage, String incidentReportApproverPackage, + String ambientContextDetectionPackage, String appPredictionServicePackage, + String companionPackageName, String retailDemoPackage, + String overlayConfigSignaturePackage, String recentsPackage) { + mDefaultAppProvider = defaultAppProvider; + mRequiredInstallerPackage = requiredInstallerPackage; + mRequiredUninstallerPackage = requiredUninstallerPackage; + mSetupWizardPackage = setupWizardPackage; + mRequiredVerifierPackage = requiredVerifierPackage; + mDefaultTextClassifierPackage = defaultTextClassifierPackage; + mSystemTextClassifierPackageName = systemTextClassifierPackageName; + mRequiredPermissionControllerPackage = requiredPermissionControllerPackage; + mConfiguratorPackage = configuratorPackage; + mIncidentReportApproverPackage = incidentReportApproverPackage; + mAmbientContextDetectionPackage = ambientContextDetectionPackage; + mAppPredictionServicePackage = appPredictionServicePackage; + mCompanionPackage = companionPackageName; + mRetailDemoPackage = retailDemoPackage; + mOverlayConfigSignaturePackage = overlayConfigSignaturePackage; + mRecentsPackage = recentsPackage; + } + + /** + * Returns the string representation of a known package. For example, + * {@link #PACKAGE_SETUP_WIZARD} is represented by the string Setup Wizard. + * + * @param knownPackage The known package. + * @return The string representation. + */ + static @NonNull String knownPackageToString(@KnownPackage int knownPackage) { + switch (knownPackage) { + case PACKAGE_SYSTEM: + return "System"; + case PACKAGE_SETUP_WIZARD: + return "Setup Wizard"; + case PACKAGE_INSTALLER: + return "Installer"; + case PACKAGE_UNINSTALLER: + return "Uninstaller"; + case PACKAGE_VERIFIER: + return "Verifier"; + case PACKAGE_BROWSER: + return "Browser"; + case PACKAGE_SYSTEM_TEXT_CLASSIFIER: + return "System Text Classifier"; + case PACKAGE_PERMISSION_CONTROLLER: + return "Permission Controller"; + case PACKAGE_WELLBEING: + return "Wellbeing"; + case PACKAGE_DOCUMENTER: + return "Documenter"; + case PACKAGE_CONFIGURATOR: + return "Configurator"; + case PACKAGE_INCIDENT_REPORT_APPROVER: + return "Incident Report Approver"; + case PACKAGE_APP_PREDICTOR: + return "App Predictor"; + case PACKAGE_WIFI: + return "Wi-Fi"; + case PACKAGE_COMPANION: + return "Companion"; + case PACKAGE_RETAIL_DEMO: + return "Retail Demo"; + case PACKAGE_OVERLAY_CONFIG_SIGNATURE: + return "Overlay Config Signature"; + case PACKAGE_RECENTS: + return "Recents"; + case PACKAGE_AMBIENT_CONTEXT_DETECTION: + return "Ambient Context Detection"; + } + return "Unknown"; + } + + String[] getKnownPackageNames(@NonNull Computer snapshot, int knownPackage, int userId) { + switch (knownPackage) { + case PACKAGE_BROWSER: + return new String[]{mDefaultAppProvider.getDefaultBrowser(userId)}; + case PACKAGE_INSTALLER: + return snapshot.filterOnlySystemPackages(mRequiredInstallerPackage); + case PACKAGE_UNINSTALLER: + return snapshot.filterOnlySystemPackages(mRequiredUninstallerPackage); + case PACKAGE_SETUP_WIZARD: + return snapshot.filterOnlySystemPackages(mSetupWizardPackage); + case PACKAGE_SYSTEM: + return new String[]{"android"}; + case PACKAGE_VERIFIER: + return snapshot.filterOnlySystemPackages(mRequiredVerifierPackage); + case PACKAGE_SYSTEM_TEXT_CLASSIFIER: + return snapshot.filterOnlySystemPackages( + mDefaultTextClassifierPackage, mSystemTextClassifierPackageName); + case PACKAGE_PERMISSION_CONTROLLER: + return snapshot.filterOnlySystemPackages(mRequiredPermissionControllerPackage); + case PACKAGE_CONFIGURATOR: + return snapshot.filterOnlySystemPackages(mConfiguratorPackage); + case PACKAGE_INCIDENT_REPORT_APPROVER: + return snapshot.filterOnlySystemPackages(mIncidentReportApproverPackage); + case PACKAGE_AMBIENT_CONTEXT_DETECTION: + return snapshot.filterOnlySystemPackages(mAmbientContextDetectionPackage); + case PACKAGE_APP_PREDICTOR: + return snapshot.filterOnlySystemPackages(mAppPredictionServicePackage); + case PACKAGE_COMPANION: + return snapshot.filterOnlySystemPackages(mCompanionPackage); + case PACKAGE_RETAIL_DEMO: + return TextUtils.isEmpty(mRetailDemoPackage) + ? ArrayUtils.emptyArray(String.class) + : new String[]{mRetailDemoPackage}; + case PACKAGE_OVERLAY_CONFIG_SIGNATURE: + return snapshot.filterOnlySystemPackages(mOverlayConfigSignaturePackage); + case PACKAGE_RECENTS: + return snapshot.filterOnlySystemPackages(mRecentsPackage); + default: + return ArrayUtils.emptyArray(String.class); + } + } +} diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 27c6d9bec2e8..af0a20ddf337 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -324,12 +324,12 @@ public class PackageDexOptimizer { String compilerFilter = getRealCompilerFilter(pkg, options.getCompilerFilter()); // If the app is used by other apps, we must not use the existing profile because it // may contain user data, unless the profile is newly created on install. - final boolean resetProfile = isProfileGuidedCompilerFilter(compilerFilter) + final boolean useCloudProfile = isProfileGuidedCompilerFilter(compilerFilter) && isUsedByOtherApps && options.getCompilationReason() != PackageManagerService.REASON_INSTALL; String dexMetadataPath = null; - if (options.isDexoptInstallWithDexMetadata() || resetProfile) { + if (options.isDexoptInstallWithDexMetadata() || useCloudProfile) { File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(new File(path)); dexMetadataPath = dexMetadataFile == null ? null : dexMetadataFile.getAbsolutePath(); @@ -339,65 +339,87 @@ public class PackageDexOptimizer { // PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA which will be a no-op with respect to // profiles. int profileAnalysisResult = PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA; - if (resetProfile) { - if (!resetProfile(pkg, profileName, path, dexMetadataPath)) { - // Fall back to use the shared filter. - compilerFilter = - PackageManagerServiceCompilerMapping.getCompilerFilterForReason( - PackageManagerService.REASON_SHARED); - } - } else if (options.isCheckForProfileUpdates()) { + if (options.isCheckForProfileUpdates()) { profileAnalysisResult = analyseProfiles(pkg, sharedGid, profileName, compilerFilter); } - - // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct - // flags. - final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, resetProfile, - options); - - for (String dexCodeIsa : dexCodeInstructionSets) { - int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter, - profileAnalysisResult, classLoaderContexts[i], dexoptFlags, sharedGid, - packageStats, options.isDowngrade(), profileName, dexMetadataPath, - options.getCompilationReason()); - // OTAPreopt doesn't have stats so don't report in that case. - if (packageStats != null) { - Trace.traceBegin(Trace.TRACE_TAG_PACKAGE_MANAGER, "dex2oat-metrics"); - try { - long sessionId = sRandom.nextLong(); - ArtStatsLogUtils.writeStatsLog( - mArtStatsLogger, - sessionId, - compilerFilter, - pkg.getUid(), - packageStats.getCompileTime(path), - dexMetadataPath, - options.getCompilationReason(), - newResult, - ArtStatsLogUtils.getApkType(path, pkg.getBaseApkPath(), - pkg.getSplitCodePaths()), - dexCodeIsa, - path); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_PACKAGE_MANAGER); + String cloudProfileName = null; + try { + if (useCloudProfile) { + cloudProfileName = "cloud-" + profileName; + if (prepareCloudProfile(pkg, cloudProfileName, path, dexMetadataPath)) { + profileName = cloudProfileName; + } else { + // Fall back to use the shared filter. + compilerFilter = + PackageManagerServiceCompilerMapping.getCompilerFilterForReason( + PackageManagerService.REASON_SHARED); + profileName = null; } + + // We still run `analyseProfiles` even if `useCloudProfile` is true because it + // merges profiles into the reference profile, which a system API + // `ArtManager.snapshotRuntimeProfile` takes snapshots from. However, we don't + // want the result to affect the decision of whether dexopt is needed. + profileAnalysisResult = PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA; } - // Should stop the operation immediately. - if (newResult == DEX_OPT_CANCELLED) { - // Even for the cancellation, return failed if has failed. - if (result == DEX_OPT_FAILED) { - return result; + // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct + // flags. + final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, + useCloudProfile, options); + + for (String dexCodeIsa : dexCodeInstructionSets) { + int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter, + profileAnalysisResult, classLoaderContexts[i], dexoptFlags, sharedGid, + packageStats, options.isDowngrade(), profileName, dexMetadataPath, + options.getCompilationReason()); + // OTAPreopt doesn't have stats so don't report in that case. + if (packageStats != null) { + Trace.traceBegin(Trace.TRACE_TAG_PACKAGE_MANAGER, "dex2oat-metrics"); + try { + long sessionId = sRandom.nextLong(); + ArtStatsLogUtils.writeStatsLog( + mArtStatsLogger, + sessionId, + compilerFilter, + pkg.getUid(), + packageStats.getCompileTime(path), + dexMetadataPath, + options.getCompilationReason(), + newResult, + ArtStatsLogUtils.getApkType(path, pkg.getBaseApkPath(), + pkg.getSplitCodePaths()), + dexCodeIsa, + path); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_PACKAGE_MANAGER); + } + } + + // Should stop the operation immediately. + if (newResult == DEX_OPT_CANCELLED) { + // Even for the cancellation, return failed if has failed. + if (result == DEX_OPT_FAILED) { + return result; + } + return newResult; + } + // The end result is: + // - FAILED if any path failed, + // - PERFORMED if at least one path needed compilation, + // - SKIPPED when all paths are up to date + if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) { + result = newResult; } - return newResult; } - // The end result is: - // - FAILED if any path failed, - // - PERFORMED if at least one path needed compilation, - // - SKIPPED when all paths are up to date - if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) { - result = newResult; + } finally { + if (cloudProfileName != null) { + try { + mInstaller.deleteReferenceProfile(pkg.getPackageName(), cloudProfileName); + } catch (InstallerException e) { + Slog.w(TAG, "Failed to cleanup cloud profile", e); + } } } } @@ -405,22 +427,25 @@ public class PackageDexOptimizer { } /** - * Resets the profiles of the dex file at {@code path} belonging to the package {@code pkg} to - * the initial state as if the package is newly installed. Returns true on success, or false - * otherwise. + * Creates a profile with the name {@code profileName} from the dex metadata file at {@code + * dexMetadataPath} for the dex file at {@code path} belonging to the package {@code pkg}. + * + * @return true on success, or false otherwise. */ @GuardedBy("mInstallLock") - private boolean resetProfile(AndroidPackage pkg, String profileName, String path, + private boolean prepareCloudProfile(AndroidPackage pkg, String profileName, String path, @Nullable String dexMetadataPath) { if (dexMetadataPath != null) { try { - mInstaller.clearAppProfiles(pkg.getPackageName(), profileName); + // Make sure we don't keep any existing contents. + mInstaller.deleteReferenceProfile(pkg.getPackageName(), profileName); + final int appId = UserHandle.getAppId(pkg.getUid()); - mInstaller.prepareAppProfile(pkg.getPackageName(), UserHandle.USER_NULL, - appId, profileName, path, dexMetadataPath); + mInstaller.prepareAppProfile(pkg.getPackageName(), UserHandle.USER_NULL, appId, + profileName, path, dexMetadataPath); return true; } catch (InstallerException e) { - Slog.w(TAG, "Failed to reset profile", e); + Slog.w(TAG, "Failed to prepare cloud profile", e); return false; } } else { @@ -835,16 +860,16 @@ public class PackageDexOptimizer { private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) { return getDexFlags((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0, info.getHiddenApiEnforcementPolicy(), info.splitDependencies, - info.requestsIsolatedSplitLoading(), compilerFilter, false /* resetProfile */, + info.requestsIsolatedSplitLoading(), compilerFilter, false /* useCloudProfile */, options); } private int getDexFlags(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting, - String compilerFilter, boolean resetProfile, DexoptOptions options) { + String compilerFilter, boolean useCloudProfile, DexoptOptions options) { return getDexFlags(pkg.isDebuggable(), AndroidPackageUtils.getHiddenApiEnforcementPolicy(pkg, pkgSetting), pkg.getSplitDependencies(), pkg.isIsolatedSplitLoading(), compilerFilter, - resetProfile, options); + useCloudProfile, options); } /** @@ -853,15 +878,15 @@ public class PackageDexOptimizer { */ private int getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy, SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading, - String compilerFilter, boolean resetProfile, DexoptOptions options) { + String compilerFilter, boolean useCloudProfile, DexoptOptions options) { // Profile guide compiled oat files should not be public unles they are based // on profiles from dex metadata archives. // The flag isDexoptInstallWithDexMetadata applies only on installs when we know that // the user does not have an existing profile. - // The flag resetProfile applies only when the existing profile is already reset. + // The flag useCloudProfile applies only when the cloud profile should be used. boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter); boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata() - || resetProfile; + || useCloudProfile; int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0; // Some apps are executed with restrictions on hidden API usage. If this app is one // of them, pass a flag to dexopt to enable the same restrictions during compilation. diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 1efaa735a56c..7c900ef9401a 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -1741,7 +1741,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static boolean isSecureFrpInstallAllowed(Context context, int callingUid) { final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); final String[] systemInstaller = pmi.getKnownPackageNames( - PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM); + KnownPackages.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM); final AndroidPackage callingInstaller = pmi.getPackage(callingUid); if (callingInstaller != null && ArrayUtils.contains(systemInstaller, callingInstaller.getPackageName())) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4c7243decb07..6cf63d10f1f1 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -655,9 +655,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService final ProtectedPackages mProtectedPackages; - @GuardedBy("mLoadedVolumes") - final ArraySet<String> mLoadedVolumes = new ArraySet<>(); - private boolean mFirstBoot; final boolean mIsEngBuild; @@ -667,7 +664,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy; @GuardedBy("mAvailableFeatures") - final ArrayMap<String, FeatureInfo> mAvailableFeatures; + private final ArrayMap<String, FeatureInfo> mAvailableFeatures; @Watched final InstantAppRegistry mInstantAppRegistry; @@ -943,6 +940,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService private final DexOptHelper mDexOptHelper; private final SuspendPackageHelper mSuspendPackageHelper; private final IntentResolverInterceptor mIntentResolverInterceptor; + private final StorageEventHelper mStorageEventHelper; /** * Invalidate the package info cache, which includes updating the cached computer. @@ -1584,7 +1582,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService } /** - * A extremely minimal constructor designed to start up a PackageManagerService instance for + * An extremely minimal constructor designed to start up a PackageManagerService instance for * testing. * * It is assumed that all methods under test will mock the internal fields and thus @@ -1689,6 +1687,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper); mIntentResolverInterceptor = null; + mStorageEventHelper = testParams.storageEventHelper; registerObservers(false); invalidatePackageInfoCache(); @@ -1841,6 +1840,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService mDexOptHelper = new DexOptHelper(this); mSuspendPackageHelper = new SuspendPackageHelper(this, mInjector, mBroadcastHelper, mProtectedPackages); + mStorageEventHelper = new StorageEventHelper(this, mDeletePackageHelper, + mRemovePackageHelper); synchronized (mLock) { // Create the computer as soon as the state objects have been installed. The @@ -4055,17 +4056,15 @@ public class PackageManagerService implements PackageSender, TestUtilityService mUserManager.systemReady(); // Watch for external volumes that come and go over time - final StorageEventHelper storageEventHelper = new StorageEventHelper(this, - mDeletePackageHelper, mRemovePackageHelper); final StorageManager storage = mInjector.getSystemService(StorageManager.class); - storage.registerListener(storageEventHelper); + storage.registerListener(mStorageEventHelper); mInstallerService.systemReady(); mPackageDexOptimizer.systemReady(); // Now that we're mostly running, clean up stale users and apps mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL); - storageEventHelper.reconcileApps(snapshotComputer(), StorageManager.UUID_PRIVATE_INTERNAL); + mStorageEventHelper.reconcileApps(snapshotComputer(), StorageManager.UUID_PRIVATE_INTERNAL); mPermissionManager.onSystemReady(); @@ -4163,20 +4162,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService } } - void dumpSnapshotStats(PrintWriter pw, boolean isBrief) { - if (mSnapshotStatistics == null) { - return; - } - int hits = 0; - synchronized (mSnapshotLock) { - if (mSnapshotComputer != null) { - hits = mSnapshotComputer.getUsed(); - } - } - final long now = SystemClock.currentTimeMicro(); - mSnapshotStatistics.dump(pw, " ", now, hits, -1, isBrief); - } - //TODO: b/111402650 private void disableSkuSpecificApps() { String[] apkList = mContext.getResources().getStringArray( @@ -4221,17 +4206,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService } } - /** - * Verify that given package is currently frozen. - */ - void checkPackageFrozen(String packageName) { - synchronized (mLock) { - if (!mFrozenPackages.containsKey(packageName)) { - Slog.wtf(TAG, "Expected " + packageName + " to be frozen!", new Throwable()); - } - } - } - /** Called by UserManagerService */ void cleanUpUser(UserManagerService userManager, @UserIdInt int userId) { synchronized (mLock) { @@ -6050,7 +6024,37 @@ public class PackageManagerService implements PackageSender, TestUtilityService @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return; - new DumpHelper(PackageManagerService.this).doDump(fd, pw, args); + final Computer snapshot = snapshotComputer(); + final KnownPackages knownPackages = new KnownPackages( + mDefaultAppProvider, + mRequiredInstallerPackage, + mRequiredUninstallerPackage, + mSetupWizardPackage, + mRequiredVerifierPackage, + mDefaultTextClassifierPackage, + mSystemTextClassifierPackageName, + mRequiredPermissionControllerPackage, + mConfiguratorPackage, + mIncidentReportApproverPackage, + mAmbientContextDetectionPackage, + mAppPredictionServicePackage, + COMPANION_PACKAGE_NAME, + mRetailDemoPackage, + mOverlayConfigSignaturePackage, + mRecentsPackage); + final ArrayMap<String, FeatureInfo> availableFeatures; + synchronized (mAvailableFeatures) { + availableFeatures = new ArrayMap<>(mAvailableFeatures); + } + final ArraySet<String> protectedBroadcasts; + synchronized (mProtectedBroadcasts) { + protectedBroadcasts = new ArraySet<>(mProtectedBroadcasts); + } + new DumpHelper(mPermissionManager, mApexManager, mStorageEventHelper, + mDomainVerificationManager, mInstallerService, mRequiredVerifierPackage, + knownPackages, mChangedPackagesTracker, availableFeatures, protectedBroadcasts, + getPerUidReadTimeouts(snapshot) + ).doDump(snapshot, fd, pw, args); } } @@ -6984,45 +6988,24 @@ public class PackageManagerService implements PackageSender, TestUtilityService String[] getKnownPackageNamesInternal(@NonNull Computer snapshot, int knownPackage, int userId) { - switch (knownPackage) { - case PackageManagerInternal.PACKAGE_BROWSER: - return new String[] { mDefaultAppProvider.getDefaultBrowser(userId) }; - case PackageManagerInternal.PACKAGE_INSTALLER: - return snapshot.filterOnlySystemPackages(mRequiredInstallerPackage); - case PackageManagerInternal.PACKAGE_UNINSTALLER: - return snapshot.filterOnlySystemPackages(mRequiredUninstallerPackage); - case PackageManagerInternal.PACKAGE_SETUP_WIZARD: - return snapshot.filterOnlySystemPackages(mSetupWizardPackage); - case PackageManagerInternal.PACKAGE_SYSTEM: - return new String[]{"android"}; - case PackageManagerInternal.PACKAGE_VERIFIER: - return snapshot.filterOnlySystemPackages(mRequiredVerifierPackage); - case PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER: - return snapshot.filterOnlySystemPackages( - mDefaultTextClassifierPackage, mSystemTextClassifierPackageName); - case PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER: - return snapshot.filterOnlySystemPackages(mRequiredPermissionControllerPackage); - case PackageManagerInternal.PACKAGE_CONFIGURATOR: - return snapshot.filterOnlySystemPackages(mConfiguratorPackage); - case PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER: - return snapshot.filterOnlySystemPackages(mIncidentReportApproverPackage); - case PackageManagerInternal.PACKAGE_AMBIENT_CONTEXT_DETECTION: - return snapshot.filterOnlySystemPackages(mAmbientContextDetectionPackage); - case PackageManagerInternal.PACKAGE_APP_PREDICTOR: - return snapshot.filterOnlySystemPackages(mAppPredictionServicePackage); - case PackageManagerInternal.PACKAGE_COMPANION: - return snapshot.filterOnlySystemPackages(COMPANION_PACKAGE_NAME); - case PackageManagerInternal.PACKAGE_RETAIL_DEMO: - return TextUtils.isEmpty(mRetailDemoPackage) - ? ArrayUtils.emptyArray(String.class) - : new String[] {mRetailDemoPackage}; - case PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE: - return snapshot.filterOnlySystemPackages(mOverlayConfigSignaturePackage); - case PackageManagerInternal.PACKAGE_RECENTS: - return snapshot.filterOnlySystemPackages(mRecentsPackage); - default: - return ArrayUtils.emptyArray(String.class); - } + return new KnownPackages( + mDefaultAppProvider, + mRequiredInstallerPackage, + mRequiredUninstallerPackage, + mSetupWizardPackage, + mRequiredVerifierPackage, + mDefaultTextClassifierPackage, + mSystemTextClassifierPackageName, + mRequiredPermissionControllerPackage, + mConfiguratorPackage, + mIncidentReportApproverPackage, + mAmbientContextDetectionPackage, + mAppPredictionServicePackage, + COMPANION_PACKAGE_NAME, + mRetailDemoPackage, + mOverlayConfigSignaturePackage, + mRecentsPackage) + .getKnownPackageNames(snapshot, knownPackage, userId); } String getActiveLauncherPackageName(int userId) { diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java index e466fe2c0e31..144231c95f75 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java @@ -115,4 +115,5 @@ public final class PackageManagerServiceTestParams { public ResolveIntentHelper resolveIntentHelper; public DexOptHelper dexOptHelper; public SuspendPackageHelper suspendPackageHelper; + public StorageEventHelper storageEventHelper; } diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java index b181cdd92379..baa3a9d85b0a 100644 --- a/services/core/java/com/android/server/pm/RemovePackageHelper.java +++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java @@ -17,6 +17,7 @@ package com.android.server.pm; import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN; +import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.os.incremental.IncrementalManager.isIncrementalPath; import static android.os.storage.StorageManager.FLAG_STORAGE_CE; import static android.os.storage.StorageManager.FLAG_STORAGE_DE; @@ -29,6 +30,7 @@ import static com.android.server.pm.PackageManagerService.TAG; import android.annotation.NonNull; import android.content.pm.PackageManager; +import android.os.Trace; import android.os.UserHandle; import android.os.incremental.IncrementalManager; import android.util.Log; @@ -334,10 +336,19 @@ final class RemovePackageHelper { mPm.mSettings.writeKernelMappingLPr(deletedPs); } } + if (removedAppId != -1) { - // A user ID was deleted here. Go through all users and remove it - // from KeyStore. - mAppDataHelper.clearKeystoreData(UserHandle.USER_ALL, removedAppId); + // A user ID was deleted here. Go through all users and remove it from KeyStore. + final int appIdToRemove = removedAppId; + mPm.mInjector.getBackgroundHandler().post(() -> { + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, + "clearKeystoreData:" + appIdToRemove); + mAppDataHelper.clearKeystoreData(UserHandle.USER_ALL, appIdToRemove); + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + }); } } } diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java index a991ed3c4792..8c6b19b3361c 100644 --- a/services/core/java/com/android/server/pm/StorageEventHelper.java +++ b/services/core/java/com/android/server/pm/StorageEventHelper.java @@ -42,15 +42,19 @@ import android.os.storage.StorageManagerInternal; import android.os.storage.VolumeInfo; import android.text.TextUtils; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; import com.android.internal.policy.AttributeCache; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import java.io.File; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -61,6 +65,9 @@ public final class StorageEventHelper extends StorageEventListener { private final DeletePackageHelper mDeletePackageHelper; private final RemovePackageHelper mRemovePackageHelper; + @GuardedBy("mLoadedVolumes") + final ArraySet<String> mLoadedVolumes = new ArraySet<>(); + // TODO(b/198166813): remove PMS dependency public StorageEventHelper(PackageManagerService pm, DeletePackageHelper deletePackageHelper, RemovePackageHelper removePackageHelper) { @@ -216,8 +223,8 @@ public final class StorageEventHelper extends StorageEventListener { if (DEBUG_INSTALL) Slog.d(TAG, "Loaded packages " + loaded); sendResourcesChangedBroadcast(true, false, loaded, null); - synchronized (mPm.mLoadedVolumes) { - mPm.mLoadedVolumes.add(vol.getId()); + synchronized (mLoadedVolumes) { + mLoadedVolumes.add(vol.getId()); } } @@ -267,8 +274,8 @@ public final class StorageEventHelper extends StorageEventListener { if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded); sendResourcesChangedBroadcast(false, false, unloaded, null); - synchronized (mPm.mLoadedVolumes) { - mPm.mLoadedVolumes.remove(vol.getId()); + synchronized (mLoadedVolumes) { + mLoadedVolumes.remove(vol.getId()); } // Try very hard to release any references to this path so we don't risk @@ -357,4 +364,24 @@ public final class StorageEventHelper extends StorageEventListener { } return codePaths; } + + public void dumpLoadedVolumes(@NonNull PrintWriter pw, @NonNull DumpState dumpState) { + if (dumpState.onTitlePrinted()) { + pw.println(); + } + final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); + ipw.println(); + ipw.println("Loaded volumes:"); + ipw.increaseIndent(); + synchronized (mLoadedVolumes) { + if (mLoadedVolumes.size() == 0) { + ipw.println("(none)"); + } else { + for (int i = 0; i < mLoadedVolumes.size(); i++) { + ipw.println(mLoadedVolumes.valueAt(i)); + } + } + } + ipw.decreaseIndent(); + } } diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java index 588dfaf6db78..860c54c31bb2 100644 --- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java +++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java @@ -16,10 +16,6 @@ package com.android.server.pm; -import static android.content.pm.PackageManagerInternal.PACKAGE_INSTALLER; -import static android.content.pm.PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER; -import static android.content.pm.PackageManagerInternal.PACKAGE_UNINSTALLER; -import static android.content.pm.PackageManagerInternal.PACKAGE_VERIFIER; import static android.os.Process.SYSTEM_UID; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; @@ -31,7 +27,6 @@ import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.IActivityManager; import android.content.Intent; -import android.content.pm.PackageManagerInternal.KnownPackage; import android.content.pm.SuspendDialogInfo; import android.os.Binder; import android.os.Bundle; @@ -489,13 +484,14 @@ public final class SuspendPackageHelper { final String activeLauncherPackageName = defaultAppProvider.getDefaultHome(userId); final String dialerPackageName = defaultAppProvider.getDefaultDialer(userId); final String requiredInstallerPackage = - getKnownPackageName(snapshot, PACKAGE_INSTALLER, userId); + getKnownPackageName(snapshot, KnownPackages.PACKAGE_INSTALLER, userId); final String requiredUninstallerPackage = - getKnownPackageName(snapshot, PACKAGE_UNINSTALLER, userId); + getKnownPackageName(snapshot, KnownPackages.PACKAGE_UNINSTALLER, userId); final String requiredVerifierPackage = - getKnownPackageName(snapshot, PACKAGE_VERIFIER, userId); + getKnownPackageName(snapshot, KnownPackages.PACKAGE_VERIFIER, userId); final String requiredPermissionControllerPackage = - getKnownPackageName(snapshot, PACKAGE_PERMISSION_CONTROLLER, userId); + getKnownPackageName(snapshot, KnownPackages.PACKAGE_PERMISSION_CONTROLLER, + userId); for (int i = 0; i < packageNames.length; i++) { canSuspend[i] = false; final String packageName = packageNames[i]; @@ -638,8 +634,8 @@ public final class SuspendPackageHelper { } } - private String getKnownPackageName(@NonNull Computer snapshot, @KnownPackage int knownPackage, - int userId) { + private String getKnownPackageName(@NonNull Computer snapshot, + @KnownPackages.KnownPackage int knownPackage, int userId) { final String[] knownPackages = mPm.getKnownPackageNamesInternal(snapshot, knownPackage, userId); return knownPackages.length > 0 ? knownPackages[0] : null; diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 36633cc635e7..849f53026c99 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -70,6 +70,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.XmlUtils; import com.android.server.LocalServices; import com.android.server.ServiceThread; +import com.android.server.pm.KnownPackages; import com.android.server.pm.permission.LegacyPermissionManagerInternal.PackagesProvider; import com.android.server.pm.permission.LegacyPermissionManagerInternal.SyncAdapterPackagesProvider; @@ -585,19 +586,19 @@ final class DefaultPermissionGrantPolicy { // Installer grantSystemFixedPermissionsToSystemPackage(pm, ArrayUtils.firstOrNull(getKnownPackages( - PackageManagerInternal.PACKAGE_INSTALLER, userId)), + KnownPackages.PACKAGE_INSTALLER, userId)), userId, STORAGE_PERMISSIONS, NOTIFICATION_PERMISSIONS); // Verifier final String verifier = ArrayUtils.firstOrNull(getKnownPackages( - PackageManagerInternal.PACKAGE_VERIFIER, userId)); + KnownPackages.PACKAGE_VERIFIER, userId)); grantSystemFixedPermissionsToSystemPackage(pm, verifier, userId, STORAGE_PERMISSIONS); grantPermissionsToSystemPackage(pm, verifier, userId, PHONE_PERMISSIONS, SMS_PERMISSIONS, NOTIFICATION_PERMISSIONS); // SetupWizard final String setupWizardPackage = ArrayUtils.firstOrNull(getKnownPackages( - PackageManagerInternal.PACKAGE_SETUP_WIZARD, userId)); + KnownPackages.PACKAGE_SETUP_WIZARD, userId)); grantPermissionsToSystemPackage(pm, setupWizardPackage, userId, PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS, CAMERA_PERMISSIONS); grantSystemFixedPermissionsToSystemPackage(pm, setupWizardPackage, userId, @@ -758,7 +759,7 @@ final class DefaultPermissionGrantPolicy { // Browser String browserPackage = ArrayUtils.firstOrNull(getKnownPackages( - PackageManagerInternal.PACKAGE_BROWSER, userId)); + KnownPackages.PACKAGE_BROWSER, userId)); if (browserPackage == null) { browserPackage = getDefaultSystemHandlerActivityPackageForCategory(pm, Intent.CATEGORY_APP_BROWSER, userId); @@ -890,7 +891,7 @@ final class DefaultPermissionGrantPolicy { // TextClassifier Service for (String textClassifierPackage : - getKnownPackages(PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER, userId)) { + getKnownPackages(KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER, userId)) { grantPermissionsToSystemPackage(pm, textClassifierPackage, userId, COARSE_BACKGROUND_LOCATION_PERMISSIONS, CONTACTS_PERMISSIONS); } 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 009d155e96ef..c524fb7ae9e5 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java @@ -126,6 +126,7 @@ import com.android.server.ServiceThread; import com.android.server.SystemConfig; import com.android.server.Watchdog; import com.android.server.pm.ApexManager; +import com.android.server.pm.KnownPackages; import com.android.server.pm.UserManagerInternal; import com.android.server.pm.UserManagerService; import com.android.server.pm.parsing.PackageInfoUtils; @@ -3323,7 +3324,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt @NonNull Permission bp) { // expect single system package String systemPackageName = ArrayUtils.firstOrNull(mPackageManagerInt.getKnownPackageNames( - PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM)); + KnownPackages.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM)); final AndroidPackage systemPackage = mPackageManagerInt.getPackage(systemPackageName); // check if the package is allow to use this signature permission. A package is allowed to @@ -3398,10 +3399,10 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt // permissions are needed by the permission controller if (!allowed && bp.isInstaller() && (ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( - PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM), + KnownPackages.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM), pkg.getPackageName()) || ArrayUtils.contains( mPackageManagerInt.getKnownPackageNames( - PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER, + KnownPackages.PACKAGE_PERMISSION_CONTROLLER, UserHandle.USER_SYSTEM), pkg.getPackageName()))) { // If this permission is to be granted to the system installer and // this app is an installer, then it gets the permission. @@ -3409,7 +3410,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt } if (!allowed && bp.isVerifier() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( - PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM), + KnownPackages.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM), pkg.getPackageName())) { // If this permission is to be granted to the system verifier and // this app is a verifier, then it gets the permission. @@ -3433,7 +3434,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt //} if (!allowed && bp.isSetup() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( - PackageManagerInternal.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM), + KnownPackages.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM), pkg.getPackageName())) { // If this permission is to be granted to the system setup wizard and // this app is a setup wizard, then it gets the permission. @@ -3441,21 +3442,21 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt } if (!allowed && bp.isSystemTextClassifier() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( - PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER, + KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER, UserHandle.USER_SYSTEM), pkg.getPackageName())) { // Special permissions for the system default text classifier. allowed = true; } if (!allowed && bp.isConfigurator() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( - PackageManagerInternal.PACKAGE_CONFIGURATOR, + KnownPackages.PACKAGE_CONFIGURATOR, UserHandle.USER_SYSTEM), pkg.getPackageName())) { // Special permissions for the device configurator. allowed = true; } if (!allowed && bp.isIncidentReportApprover() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( - PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER, + KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER, UserHandle.USER_SYSTEM), pkg.getPackageName())) { // If this permission is to be granted to the incident report approver and // this app is the incident report approver, then it gets the permission. @@ -3463,28 +3464,28 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt } if (!allowed && bp.isAppPredictor() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( - PackageManagerInternal.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM), + KnownPackages.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM), pkg.getPackageName())) { // Special permissions for the system app predictor. allowed = true; } if (!allowed && bp.isCompanion() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( - PackageManagerInternal.PACKAGE_COMPANION, UserHandle.USER_SYSTEM), + KnownPackages.PACKAGE_COMPANION, UserHandle.USER_SYSTEM), pkg.getPackageName())) { // Special permissions for the system companion device manager. allowed = true; } if (!allowed && bp.isRetailDemo() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( - PackageManagerInternal.PACKAGE_RETAIL_DEMO, UserHandle.USER_SYSTEM), + KnownPackages.PACKAGE_RETAIL_DEMO, UserHandle.USER_SYSTEM), pkg.getPackageName()) && isProfileOwner(pkg.getUid())) { // Special permission granted only to the OEM specified retail demo app allowed = true; } if (!allowed && bp.isRecents() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( - PackageManagerInternal.PACKAGE_RECENTS, UserHandle.USER_SYSTEM), + KnownPackages.PACKAGE_RECENTS, UserHandle.USER_SYSTEM), pkg.getPackageName())) { // Special permission for the recents app. allowed = true; diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java index cf9370d12735..9aa53f18d0aa 100644 --- a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java +++ b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java @@ -47,13 +47,11 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import com.android.server.IntentResolver; import com.android.server.pm.Computer; -import com.android.server.pm.DumpState; import com.android.server.pm.PackageManagerException; import com.android.server.pm.UserManagerService; import com.android.server.pm.UserNeedsBadgingCache; import com.android.server.pm.parsing.PackageInfoUtils; import com.android.server.pm.parsing.pkg.AndroidPackage; -import com.android.server.pm.parsing.pkg.AndroidPackageUtils; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.PackageStateUtils; import com.android.server.pm.pkg.PackageUserStateInternal; @@ -76,7 +74,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Function; @@ -271,119 +268,6 @@ public class ComponentResolver extends ComponentResolverLocked implements Snappa } } - public void dumpActivityResolvers(PrintWriter pw, DumpState dumpState, String packageName) { - synchronized (mLock) { - if (mActivities.dump(pw, dumpState.getTitlePrinted() ? "\nActivity Resolver Table:" - : "Activity Resolver Table:", " ", packageName, - dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { - dumpState.setTitlePrinted(true); - } - } - } - - public void dumpProviderResolvers(PrintWriter pw, DumpState dumpState, String packageName) { - synchronized (mLock) { - if (mProviders.dump(pw, dumpState.getTitlePrinted() ? "\nProvider Resolver Table:" - : "Provider Resolver Table:", " ", packageName, - dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { - dumpState.setTitlePrinted(true); - } - } - } - - public void dumpReceiverResolvers(PrintWriter pw, DumpState dumpState, String packageName) { - synchronized (mLock) { - if (mReceivers.dump(pw, dumpState.getTitlePrinted() ? "\nReceiver Resolver Table:" - : "Receiver Resolver Table:", " ", packageName, - dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { - dumpState.setTitlePrinted(true); - } - } - } - - public void dumpServiceResolvers(PrintWriter pw, DumpState dumpState, String packageName) { - synchronized (mLock) { - if (mServices.dump(pw, dumpState.getTitlePrinted() ? "\nService Resolver Table:" - : "Service Resolver Table:", " ", packageName, - dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { - dumpState.setTitlePrinted(true); - } - } - } - - public void dumpContentProviders(@NonNull Computer computer, PrintWriter pw, - DumpState dumpState, String packageName) { - synchronized (mLock) { - boolean printedSomething = false; - for (ParsedProvider p : mProviders.mProviders.values()) { - if (packageName != null && !packageName.equals(p.getPackageName())) { - continue; - } - if (!printedSomething) { - if (dumpState.onTitlePrinted()) { - pw.println(); - } - pw.println("Registered ContentProviders:"); - printedSomething = true; - } - pw.print(" "); - ComponentName.printShortString(pw, p.getPackageName(), p.getName()); - pw.println(":"); - pw.print(" "); - pw.println(p.toString()); - } - printedSomething = false; - for (Map.Entry<String, ParsedProvider> entry : - mProvidersByAuthority.entrySet()) { - ParsedProvider p = entry.getValue(); - if (packageName != null && !packageName.equals(p.getPackageName())) { - continue; - } - if (!printedSomething) { - if (dumpState.onTitlePrinted()) { - pw.println(); - } - pw.println("ContentProvider Authorities:"); - printedSomething = true; - } - pw.print(" ["); - pw.print(entry.getKey()); - pw.println("]:"); - pw.print(" "); - pw.println(p.toString()); - - AndroidPackage pkg = computer.getPackage(p.getPackageName()); - - if (pkg != null) { - pw.print(" applicationInfo="); - pw.println(AndroidPackageUtils.generateAppInfoWithoutState(pkg)); - } - } - } - } - - public void dumpServicePermissions(PrintWriter pw, DumpState dumpState) { - synchronized (mLock) { - if (dumpState.onTitlePrinted()) pw.println(); - pw.println("Service permissions:"); - - final Iterator<Pair<ParsedService, ParsedIntentInfo>> filterIterator = - mServices.filterIterator(); - while (filterIterator.hasNext()) { - final Pair<ParsedService, ParsedIntentInfo> pair = filterIterator.next(); - ParsedService service = pair.first; - - final String permission = service.getPermission(); - if (permission != null) { - pw.print(" "); - pw.print(service.getComponentName().flattenToShortString()); - pw.print(": "); - pw.println(permission); - } - } - } - } - @GuardedBy("mLock") private void addActivitiesLocked(@NonNull Computer computer, AndroidPackage pkg, List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents, boolean chatty) { diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolverApi.java b/services/core/java/com/android/server/pm/resolution/ComponentResolverApi.java index b6f2b2a0451b..b8e4c8d2a51f 100644 --- a/services/core/java/com/android/server/pm/resolution/ComponentResolverApi.java +++ b/services/core/java/com/android/server/pm/resolution/ComponentResolverApi.java @@ -26,10 +26,12 @@ import android.content.pm.ResolveInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.server.pm.Computer; +import com.android.server.pm.DumpState; import com.android.server.pm.pkg.component.ParsedActivity; import com.android.server.pm.pkg.component.ParsedProvider; import com.android.server.pm.pkg.component.ParsedService; +import java.io.PrintWriter; import java.util.List; public interface ComponentResolverApi { @@ -97,4 +99,21 @@ public interface ComponentResolverApi { void querySyncProviders(@NonNull Computer computer, @NonNull List<String> outNames, @NonNull List<ProviderInfo> outInfo, boolean safeMode, @UserIdInt int userId); + + void dumpActivityResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState, + @NonNull String packageName); + + void dumpProviderResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState, + @NonNull String packageName); + + void dumpReceiverResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState, + @NonNull String packageName); + + void dumpServiceResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState, + @NonNull String packageName); + + void dumpContentProviders(@NonNull Computer computer, @NonNull PrintWriter pw, + @NonNull DumpState dumpState, @NonNull String packageName); + + void dumpServicePermissions(@NonNull PrintWriter pw, @NonNull DumpState dumpState); } diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java b/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java index 6b50fc6d306d..c01cecff9f61 100644 --- a/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java +++ b/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java @@ -26,21 +26,28 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.os.UserHandle; import android.util.ArrayMap; +import android.util.Pair; import com.android.server.pm.Computer; +import com.android.server.pm.DumpState; import com.android.server.pm.UserManagerService; import com.android.server.pm.parsing.PackageInfoUtils; import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.PackageUserStateInternal; import com.android.server.pm.pkg.component.ParsedActivity; +import com.android.server.pm.pkg.component.ParsedIntentInfo; import com.android.server.pm.pkg.component.ParsedMainComponent; import com.android.server.pm.pkg.component.ParsedProvider; import com.android.server.pm.pkg.component.ParsedService; import com.android.server.utils.WatchableImpl; +import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; +import java.util.Map; public abstract class ComponentResolverBase extends WatchableImpl implements ComponentResolverApi { @@ -305,4 +312,116 @@ public abstract class ComponentResolverBase extends WatchableImpl implements Com outInfo.add(info); } } + + @Override + public void dumpActivityResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState, + @NonNull String packageName) { + if (mActivities.dump(pw, dumpState.getTitlePrinted() ? "\nActivity Resolver Table:" + : "Activity Resolver Table:", " ", packageName, + dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { + dumpState.setTitlePrinted(true); + } + } + + @Override + public void dumpProviderResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState, + @NonNull String packageName) { + if (mProviders.dump(pw, dumpState.getTitlePrinted() ? "\nProvider Resolver Table:" + : "Provider Resolver Table:", " ", packageName, + dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { + dumpState.setTitlePrinted(true); + } + } + + @Override + public void dumpReceiverResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState, + @NonNull String packageName) { + if (mReceivers.dump(pw, dumpState.getTitlePrinted() ? "\nReceiver Resolver Table:" + : "Receiver Resolver Table:", " ", packageName, + dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { + dumpState.setTitlePrinted(true); + } + } + + @Override + public void dumpServiceResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState, + @NonNull String packageName) { + if (mServices.dump(pw, dumpState.getTitlePrinted() ? "\nService Resolver Table:" + : "Service Resolver Table:", " ", packageName, + dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { + dumpState.setTitlePrinted(true); + } + } + + @Override + public void dumpContentProviders(@NonNull Computer computer, @NonNull PrintWriter pw, + @NonNull DumpState dumpState, @NonNull String packageName) { + boolean printedSomething = false; + for (ParsedProvider p : mProviders.mProviders.values()) { + if (packageName != null && !packageName.equals(p.getPackageName())) { + continue; + } + if (!printedSomething) { + if (dumpState.onTitlePrinted()) { + pw.println(); + } + pw.println("Registered ContentProviders:"); + printedSomething = true; + } + pw.print(" "); + ComponentName.printShortString(pw, p.getPackageName(), p.getName()); + pw.println(":"); + pw.print(" "); + pw.println(p.toString()); + } + printedSomething = false; + for (Map.Entry<String, ParsedProvider> entry : + mProvidersByAuthority.entrySet()) { + ParsedProvider p = entry.getValue(); + if (packageName != null && !packageName.equals(p.getPackageName())) { + continue; + } + if (!printedSomething) { + if (dumpState.onTitlePrinted()) { + pw.println(); + } + pw.println("ContentProvider Authorities:"); + printedSomething = true; + } + pw.print(" ["); + pw.print(entry.getKey()); + pw.println("]:"); + pw.print(" "); + pw.println(p.toString()); + + AndroidPackage pkg = computer.getPackage(p.getPackageName()); + + if (pkg != null) { + pw.print(" applicationInfo="); + pw.println(AndroidPackageUtils.generateAppInfoWithoutState(pkg)); + } + } + } + + @Override + public void dumpServicePermissions(@NonNull PrintWriter pw, @NonNull DumpState dumpState) { + if (dumpState.onTitlePrinted()) pw.println(); + pw.println("Service permissions:"); + + final Iterator<Pair<ParsedService, ParsedIntentInfo>> filterIterator = + mServices.filterIterator(); + while (filterIterator.hasNext()) { + final Pair<ParsedService, ParsedIntentInfo> pair = filterIterator.next(); + ParsedService service = pair.first; + + final String permission = service.getPermission(); + if (permission != null) { + pw.print(" "); + pw.print(service.getComponentName().flattenToShortString()); + pw.print(": "); + pw.println(permission); + } + } + } + } diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolverLocked.java b/services/core/java/com/android/server/pm/resolution/ComponentResolverLocked.java index ecc53ebf3d10..0c84f4c53dfe 100644 --- a/services/core/java/com/android/server/pm/resolution/ComponentResolverLocked.java +++ b/services/core/java/com/android/server/pm/resolution/ComponentResolverLocked.java @@ -25,12 +25,14 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import com.android.server.pm.Computer; +import com.android.server.pm.DumpState; import com.android.server.pm.PackageManagerTracedLock; import com.android.server.pm.UserManagerService; import com.android.server.pm.pkg.component.ParsedActivity; import com.android.server.pm.pkg.component.ParsedProvider; import com.android.server.pm.pkg.component.ParsedService; +import java.io.PrintWriter; import java.util.List; public abstract class ComponentResolverLocked extends ComponentResolverBase { @@ -189,4 +191,51 @@ public abstract class ComponentResolverLocked extends ComponentResolverBase { super.querySyncProviders(computer, outNames, outInfo, safeMode, userId); } } + + @Override + public void dumpActivityResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState, + @NonNull String packageName) { + synchronized (mLock) { + super.dumpActivityResolvers(pw, dumpState, packageName); + } + } + + @Override + public void dumpProviderResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState, + @NonNull String packageName) { + synchronized (mLock) { + super.dumpProviderResolvers(pw, dumpState, packageName); + } + } + + @Override + public void dumpReceiverResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState, + @NonNull String packageName) { + synchronized (mLock) { + super.dumpReceiverResolvers(pw, dumpState, packageName); + } + } + + @Override + public void dumpServiceResolvers(@NonNull PrintWriter pw, @NonNull DumpState dumpState, + @NonNull String packageName) { + synchronized (mLock) { + super.dumpServiceResolvers(pw, dumpState, packageName); + } + } + + @Override + public void dumpContentProviders(@NonNull Computer computer, @NonNull PrintWriter pw, + @NonNull DumpState dumpState, @NonNull String packageName) { + synchronized (mLock) { + super.dumpContentProviders(computer, pw, dumpState, packageName); + } + } + + @Override + public void dumpServicePermissions(@NonNull PrintWriter pw, @NonNull DumpState dumpState) { + synchronized (mLock) { + super.dumpServicePermissions(pw, dumpState); + } + } } diff --git a/services/core/java/com/android/server/utils/WatchedArraySet.java b/services/core/java/com/android/server/utils/WatchedArraySet.java index 5070dd1675d3..ec80261a2196 100644 --- a/services/core/java/com/android/server/utils/WatchedArraySet.java +++ b/services/core/java/com/android/server/utils/WatchedArraySet.java @@ -20,6 +20,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.util.ArraySet; +import java.util.Collection; + /** * WatchedArraySet is an {@link android.util.ArraySet} that can report changes to itself. If its * values are {@link Watchable} then the WatchedArraySet will also report changes to the values. @@ -280,13 +282,11 @@ public class WatchedArraySet<E> extends WatchableImpl /** * Perform a {@link #add(Object)} of all values in <var>array</var> - * @param array The array whose contents are to be retrieved. + * @param collection The collection whose contents are to be retrieved. */ - public void addAll(ArraySet<? extends E> array) { - final int end = array.size(); - for (int i = 0; i < end; i++) { - add(array.valueAt(i)); - } + public void addAll(Collection<? extends E> collection) { + mStorage.addAll(collection); + onChanged(); } /** diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index 8018d5652b1b..5fdcd690b5e2 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -85,6 +85,7 @@ import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.protolog.common.ProtoLog; import com.android.server.LocalServices; import com.android.server.Watchdog; +import com.android.server.pm.KnownPackages; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.uri.NeededUriGrants; import com.android.server.vr.VrManagerInternal; @@ -627,7 +628,7 @@ class ActivityClientController extends IActivityClientController.Stub { return true; } final String[] installerNames = pm.getKnownPackageNames( - PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.getUserId(uid)); + KnownPackages.PACKAGE_INSTALLER, UserHandle.getUserId(uid)); return installerNames.length > 0 && callingPkg.getPackageName().equals(installerNames[0]); } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 52651b9fd076..798719b9c51f 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -53,6 +53,7 @@ import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import static android.view.View.GONE; +import static android.view.ViewRootImpl.LOCAL_LAYOUT; import static android.view.WindowInsets.Type.displayCutout; import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.systemBars; @@ -2647,29 +2648,27 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mCurrentPrivacyIndicatorBounds = mCurrentPrivacyIndicatorBounds.updateStaticBounds(staticBounds); if (!Objects.equals(oldBounds, mCurrentPrivacyIndicatorBounds)) { - final DisplayInfo info = mDisplayInfo; - if (mDisplayFrames.onDisplayInfoUpdated(info, - calculateDisplayCutoutForRotation(info.rotation), - calculateRoundedCornersForRotation(info.rotation), - calculatePrivacyIndicatorBoundsForRotation(info.rotation))) { - mInsetsStateController.onDisplayInfoUpdated(true); - } + updateDisplayFrames(false /* insetsSourceMayChange */, true /* notifyInsetsChange */); } } void onDisplayInfoChanged() { - final DisplayInfo info = mDisplayInfo; - if (mDisplayFrames.onDisplayInfoUpdated(info, - calculateDisplayCutoutForRotation(info.rotation), - calculateRoundedCornersForRotation(info.rotation), - calculatePrivacyIndicatorBoundsForRotation(info.rotation))) { - // TODO(b/161810301): Set notifyInsetsChange to true while the server no longer performs - // layout. - mInsetsStateController.onDisplayInfoUpdated(false /* notifyInsetsChanged */); - } + updateDisplayFrames(LOCAL_LAYOUT, LOCAL_LAYOUT); mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp(); - mInputMonitor.layoutInputConsumers(info.logicalWidth, info.logicalHeight); - mDisplayPolicy.onDisplayInfoChanged(info); + mInputMonitor.layoutInputConsumers(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); + mDisplayPolicy.onDisplayInfoChanged(mDisplayInfo); + } + + private void updateDisplayFrames(boolean insetsSourceMayChange, boolean notifyInsetsChange) { + if (mDisplayFrames.update(mDisplayInfo, + calculateDisplayCutoutForRotation(mDisplayInfo.rotation), + calculateRoundedCornersForRotation(mDisplayInfo.rotation), + calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation))) { + if (insetsSourceMayChange) { + mDisplayPolicy.updateInsetsSourceFramesExceptIme(mDisplayFrames); + } + mInsetsStateController.onDisplayFramesUpdated(notifyInsetsChange); + } } @Override @@ -3979,6 +3978,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } ProtoLog.i(WM_DEBUG_IME, "setInputMethodTarget %s", target); + final boolean layeringTargetChanged = target != mImeLayeringTarget; mImeLayeringTarget = target; // 1. Reparent the IME container window to the target root DA to get the correct bounds and @@ -4006,7 +4006,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // 4. Update the IME control target to apply any inset change and animation. // 5. Reparent the IME container surface to either the input target app, or the IME window // parent. - updateImeControlTarget(true /* forceUpdateImeParent */); + updateImeControlTarget(layeringTargetChanged); } @VisibleForTesting diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java index 45d7141fd556..76aa7f963aa6 100644 --- a/services/core/java/com/android/server/wm/DisplayFrames.java +++ b/services/core/java/com/android/server/wm/DisplayFrames.java @@ -64,26 +64,26 @@ public class DisplayFrames { PrivacyIndicatorBounds indicatorBounds) { mDisplayId = displayId; mInsetsState = insetsState; - onDisplayInfoUpdated(info, displayCutout, roundedCorners, indicatorBounds); + update(info, displayCutout, roundedCorners, indicatorBounds); } /** - * Update {@link DisplayFrames} when {@link DisplayInfo} is updated. + * This is called when {@link DisplayInfo} or {@link PrivacyIndicatorBounds} is updated. * * @param info the updated {@link DisplayInfo}. * @param displayCutout the updated {@link DisplayCutout}. * @param roundedCorners the updated {@link RoundedCorners}. - * @return {@code true} if the insets state has been changed; {@code false} otherwise. + * @param indicatorBounds the updated {@link PrivacyIndicatorBounds}. + * @return {@code true} if anything has been changed; {@code false} otherwise. */ - public boolean onDisplayInfoUpdated(DisplayInfo info, @NonNull WmDisplayCutout displayCutout, + public boolean update(DisplayInfo info, @NonNull WmDisplayCutout displayCutout, @NonNull RoundedCorners roundedCorners, @NonNull PrivacyIndicatorBounds indicatorBounds) { - mRotation = info.rotation; - final InsetsState state = mInsetsState; final Rect safe = mDisplayCutoutSafe; final DisplayCutout cutout = displayCutout.getDisplayCutout(); if (mDisplayWidth == info.logicalWidth && mDisplayHeight == info.logicalHeight + && mRotation != info.rotation && state.getDisplayCutout().equals(cutout) && state.getRoundedCorners().equals(roundedCorners) && state.getPrivacyIndicatorBounds().equals(indicatorBounds)) { @@ -91,6 +91,7 @@ public class DisplayFrames { } mDisplayWidth = info.logicalWidth; mDisplayHeight = info.logicalHeight; + mRotation = info.rotation; final Rect unrestricted = mUnrestricted; unrestricted.set(0, 0, mDisplayWidth, mDisplayHeight); state.setDisplayFrame(unrestricted); diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 4573ede13f7f..3d826bf99df0 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1498,10 +1498,6 @@ public class DisplayPolicy { } } - // TODO(b/161810301): No one is calling this since we haven't moved window layout to the client. - // When that happens, this should be called when the display rotation is - // changed, so that we can dispatch the correct insets to all the clients - // before the insets source windows report their frames to the server. void updateInsetsSourceFramesExceptIme(DisplayFrames displayFrames) { for (int i = mInsetsSourceWindowsExceptIme.size() - 1; i >= 0; i--) { final WindowState win = mInsetsSourceWindowsExceptIme.valueAt(i); diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index a19d72e37124..ed771c202c04 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -177,7 +177,7 @@ class InsetsStateController { } } - void onDisplayInfoUpdated(boolean notifyInsetsChange) { + void onDisplayFramesUpdated(boolean notifyInsetsChange) { final ArrayList<WindowState> insetsChangedWindows = new ArrayList<>(); mDisplayContent.forAllWindows(w -> { w.mAboveInsetsState.set(mState, displayCutout()); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 0542c0be5790..5918a88d5736 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -26,7 +26,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; @@ -4341,9 +4340,7 @@ class Task extends TaskFragment { int elevation = 0; // Get elevation for a specific windowing mode. - if (inPinnedWindowingMode()) { - elevation = PINNED_WINDOWING_MODE_ELEVATION_IN_DIP; - } else if (inFreeformWindowingMode()) { + if (inFreeformWindowingMode()) { elevation = taskIsFocused ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; } else { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 4175da89cf8b..7d3c784e4f16 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -278,7 +278,6 @@ import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Build; import android.os.Bundle; -import android.os.CancellationSignal; import android.os.Environment; import android.os.Handler; import android.os.IBinder; @@ -7235,47 +7234,45 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Preconditions.checkState(admin != null, "Lost mode location updates can only be sent on an organization-owned device."); mInjector.binderWithCleanCallingIdentity(() -> { - final List<String> providers = - mInjector.getLocationManager().getAllProviders().stream() - .filter(mInjector.getLocationManager()::isProviderEnabled) - .collect(Collectors.toList()); - if (providers.isEmpty()) { - future.complete(false); - return; - } - - final CancellationSignal cancellationSignal = new CancellationSignal(); - List<String> providersWithNullLocation = new ArrayList<String>(); - for (String provider : providers) { - mInjector.getLocationManager().getCurrentLocation(provider, cancellationSignal, - mContext.getMainExecutor(), location -> { - if (cancellationSignal.isCanceled()) { - return; - } else if (location != null) { - sendLostModeLocationUpdate(admin, location); - cancellationSignal.cancel(); - future.complete(true); - } else { - // location == null, provider wasn't able to get location, see - // if there are more providers - providersWithNullLocation.add(provider); - if (providers.size() == providersWithNullLocation.size()) { - future.complete(false); - } - } - } - ); - } + String[] providers = {LocationManager.FUSED_PROVIDER, + LocationManager.NETWORK_PROVIDER, LocationManager.GPS_PROVIDER}; + tryRetrieveAndSendLocationUpdate(admin, future, providers, /* index= */ 0); }); } } - private void sendLostModeLocationUpdate(ActiveAdmin admin, Location location) { + /** Send lost mode location updates recursively, in order of the list of location providers. */ + private void tryRetrieveAndSendLocationUpdate(ActiveAdmin admin, + AndroidFuture<Boolean> future, String[] providers, int index) { + // None of the providers were able to get location, return false + if (index == providers.length) { + future.complete(false); + return; + } + if (mInjector.getLocationManager().isProviderEnabled(providers[index])) { + mInjector.getLocationManager().getCurrentLocation(providers[index], + /* cancellationSignal= */ null, mContext.getMainExecutor(), location -> { + if (location != null) { + mContext.sendBroadcastAsUser( + newLostModeLocationUpdateIntent(admin, location), + admin.getUserHandle()); + future.complete(true); + } else { + tryRetrieveAndSendLocationUpdate(admin, future, providers, index + 1); + } + } + ); + } else { + tryRetrieveAndSendLocationUpdate(admin, future, providers, index + 1); + } + } + + private Intent newLostModeLocationUpdateIntent(ActiveAdmin admin, Location location) { final Intent intent = new Intent( DevicePolicyManager.ACTION_LOST_MODE_LOCATION_UPDATE); intent.putExtra(DevicePolicyManager.EXTRA_LOST_MODE_LOCATION, location); intent.setPackage(admin.info.getPackageName()); - mContext.sendBroadcastAsUser(intent, admin.getUserHandle()); + return intent; } /** diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index 4a51e41b1dc5..c9523ec16b8f 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -58,6 +58,7 @@ import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION; import static com.android.server.alarm.AlarmManagerService.ACTIVE_INDEX; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.APP_STANDBY_BUCKET_CHANGED; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHARGING_STATUS_CHANGED; +import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.EXACT_ALARM_DENY_LIST_PACKAGES_ADDED; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.EXACT_ALARM_DENY_LIST_PACKAGES_REMOVED; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES; @@ -1044,9 +1045,19 @@ public class AlarmManagerServiceTest { final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); verify(mService.mHandler, atLeastOnce()).sendMessageAtTime(messageCaptor.capture(), anyLong()); - final Message lastMessage = messageCaptor.getValue(); - assertEquals("Unexpected message send to handler", what, lastMessage.what); - mService.mHandler.handleMessage(lastMessage); + + Message expectedMessage = null; + final ArrayList<Integer> sentMessages = new ArrayList<>(); + for (Message sentMessage : messageCaptor.getAllValues()) { + if (sentMessage.what == what) { + expectedMessage = sentMessage; + } + sentMessages.add(sentMessage.what); + } + + assertNotNull("Unexpected messages sent to handler. Expected: " + what + ", sent: " + + sentMessages, expectedMessage); + mService.mHandler.handleMessage(expectedMessage); } @Test @@ -2109,16 +2120,16 @@ public class AlarmManagerServiceTest { public void hasScheduleExactAlarmBinderCallNotDenyListed() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - mockExactAlarmPermissionGrant(true, false, MODE_DEFAULT); + mockScheduleExactAlarmState(true, false, MODE_DEFAULT); assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED); + mockScheduleExactAlarmState(true, false, MODE_ALLOWED); assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - mockExactAlarmPermissionGrant(true, false, MODE_ERRORED); + mockScheduleExactAlarmState(true, false, MODE_ERRORED); assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - mockExactAlarmPermissionGrant(true, false, MODE_IGNORED); + mockScheduleExactAlarmState(true, false, MODE_IGNORED); assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); } @@ -2126,16 +2137,16 @@ public class AlarmManagerServiceTest { public void hasScheduleExactAlarmBinderCallDenyListed() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - mockExactAlarmPermissionGrant(true, true, MODE_ERRORED); + mockScheduleExactAlarmState(true, true, MODE_ERRORED); assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - mockExactAlarmPermissionGrant(true, true, MODE_DEFAULT); + mockScheduleExactAlarmState(true, true, MODE_DEFAULT); assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - mockExactAlarmPermissionGrant(true, true, MODE_IGNORED); + mockScheduleExactAlarmState(true, true, MODE_IGNORED); assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - mockExactAlarmPermissionGrant(true, true, MODE_ALLOWED); + mockScheduleExactAlarmState(true, true, MODE_ALLOWED); assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); } @@ -2148,13 +2159,13 @@ public class AlarmManagerServiceTest { public void hasScheduleExactAlarmBinderCallNotDeclared() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - mockExactAlarmPermissionGrant(false, false, MODE_DEFAULT); + mockScheduleExactAlarmState(false, false, MODE_DEFAULT); assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - mockExactAlarmPermissionGrant(false, false, MODE_ALLOWED); + mockScheduleExactAlarmState(false, false, MODE_ALLOWED); assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - mockExactAlarmPermissionGrant(false, true, MODE_ALLOWED); + mockScheduleExactAlarmState(false, true, MODE_ALLOWED); assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); } @@ -2162,10 +2173,17 @@ public class AlarmManagerServiceTest { public void canScheduleExactAlarmsBinderCallChangeDisabled() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false); - mockExactAlarmPermissionGrant(false, true, MODE_DEFAULT); + // canScheduleExactAlarms should be true regardless of any permission state. + mockUseExactAlarmState(true); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); - mockExactAlarmPermissionGrant(true, false, MODE_ERRORED); + mockUseExactAlarmState(false); + assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); + + mockScheduleExactAlarmState(false, true, MODE_DEFAULT); + assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); + + mockScheduleExactAlarmState(true, false, MODE_ERRORED); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); } @@ -2173,44 +2191,45 @@ public class AlarmManagerServiceTest { public void canScheduleExactAlarmsBinderCall() throws RemoteException { // Policy permission is denied in setUp(). mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); + mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true); // No permission, no exemption. - mockExactAlarmPermissionGrant(true, true, MODE_DEFAULT); + mockScheduleExactAlarmState(true, true, MODE_DEFAULT); assertFalse(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); // No permission, no exemption. - mockExactAlarmPermissionGrant(true, false, MODE_ERRORED); + mockScheduleExactAlarmState(true, false, MODE_ERRORED); assertFalse(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); // Policy permission only, no exemption. - mockExactAlarmPermissionGrant(true, false, MODE_ERRORED); - doReturn(PermissionChecker.PERMISSION_GRANTED).when( - () -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext), - eq(Manifest.permission.USE_EXACT_ALARM), anyInt(), eq(TEST_CALLING_UID), - eq(TEST_CALLING_PACKAGE))); + mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockUseExactAlarmState(true); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); - // Permission, no exemption. - mockExactAlarmPermissionGrant(true, false, MODE_DEFAULT); + mockUseExactAlarmState(false); + + // User permission only, no exemption. + mockScheduleExactAlarmState(true, false, MODE_DEFAULT); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); - // Permission, no exemption. - mockExactAlarmPermissionGrant(true, true, MODE_ALLOWED); + // User permission only, no exemption. + mockScheduleExactAlarmState(true, true, MODE_ALLOWED); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); // No permission, exemption. - mockExactAlarmPermissionGrant(true, false, MODE_ERRORED); + mockScheduleExactAlarmState(true, false, MODE_ERRORED); when(mDeviceIdleInternal.isAppOnWhitelist(TEST_CALLING_UID)).thenReturn(true); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); // No permission, exemption. - mockExactAlarmPermissionGrant(true, false, MODE_ERRORED); + mockScheduleExactAlarmState(true, false, MODE_ERRORED); when(mDeviceIdleInternal.isAppOnWhitelist(TEST_CALLING_UID)).thenReturn(false); doReturn(true).when(() -> UserHandle.isCore(TEST_CALLING_UID)); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); - // Both permission and exemption. - mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED); + // Both permissions and exemption. + mockScheduleExactAlarmState(true, false, MODE_ALLOWED); + mockUseExactAlarmState(true); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); } @@ -2237,6 +2256,8 @@ public class AlarmManagerServiceTest { verify(mService, never()).hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID); + verify(mService, never()).hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, + TEST_CALLING_UID); verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt()); } @@ -2313,7 +2334,7 @@ public class AlarmManagerServiceTest { public void alarmClockBinderCall() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED); + mockScheduleExactAlarmState(true, false, MODE_ALLOWED); final PendingIntent alarmPi = getNewMockPendingIntent(); final AlarmManager.AlarmClockInfo alarmClock = mock(AlarmManager.AlarmClockInfo.class); @@ -2335,7 +2356,7 @@ public class AlarmManagerServiceTest { assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type); } - private void mockExactAlarmPermissionGrant(boolean declared, boolean denyList, int mode) { + private void mockScheduleExactAlarmState(boolean declared, boolean denyList, int mode) { String[] requesters = declared ? new String[]{TEST_CALLING_PACKAGE} : EmptyArray.STRING; when(mPermissionManagerInternal.getAppOpPermissionPackages(SCHEDULE_EXACT_ALARM)) .thenReturn(requesters); @@ -2350,12 +2371,21 @@ public class AlarmManagerServiceTest { TEST_CALLING_PACKAGE)).thenReturn(mode); } + private void mockUseExactAlarmState(boolean granted) { + final int result = granted ? PermissionChecker.PERMISSION_GRANTED + : PermissionChecker.PERMISSION_HARD_DENIED; + doReturn(result).when( + () -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext), + eq(Manifest.permission.USE_EXACT_ALARM), anyInt(), eq(TEST_CALLING_UID), + eq(TEST_CALLING_PACKAGE))); + } + @Test public void alarmClockBinderCallWithoutPermission() throws RemoteException { setDeviceConfigBoolean(KEY_CRASH_NON_CLOCK_APPS, true); mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - mockExactAlarmPermissionGrant(true, false, MODE_ERRORED); + mockScheduleExactAlarmState(true, false, MODE_ERRORED); when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true); final PendingIntent alarmPi = getNewMockPendingIntent(); @@ -2377,7 +2407,7 @@ public class AlarmManagerServiceTest { public void exactBinderCallWithPermission() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED); + mockScheduleExactAlarmState(true, false, MODE_ALLOWED); final PendingIntent alarmPi = getNewMockPendingIntent(); mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0, 0, alarmPi, null, null, null, null); @@ -2401,7 +2431,7 @@ public class AlarmManagerServiceTest { public void exactBinderCallWithAllowlist() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); // If permission is denied, only then allowlist will be checked. - mockExactAlarmPermissionGrant(true, false, MODE_ERRORED); + mockScheduleExactAlarmState(true, false, MODE_ERRORED); when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true); final PendingIntent alarmPi = getNewMockPendingIntent(); @@ -2421,7 +2451,7 @@ public class AlarmManagerServiceTest { public void exactAllowWhileIdleBinderCallWithPermission() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED); + mockScheduleExactAlarmState(true, false, MODE_ALLOWED); final PendingIntent alarmPi = getNewMockPendingIntent(); mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0, FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null); @@ -2444,7 +2474,7 @@ public class AlarmManagerServiceTest { public void exactAllowWhileIdleBinderCallWithAllowlist() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); // If permission is denied, only then allowlist will be checked. - mockExactAlarmPermissionGrant(true, false, MODE_ERRORED); + mockScheduleExactAlarmState(true, false, MODE_ERRORED); when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true); final PendingIntent alarmPi = getNewMockPendingIntent(); @@ -2471,7 +2501,7 @@ public class AlarmManagerServiceTest { setDeviceConfigBoolean(KEY_CRASH_NON_CLOCK_APPS, true); mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - mockExactAlarmPermissionGrant(true, false, MODE_ERRORED); + mockScheduleExactAlarmState(true, false, MODE_ERRORED); when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(false); final PendingIntent alarmPi = getNewMockPendingIntent(); @@ -2503,6 +2533,7 @@ public class AlarmManagerServiceTest { FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null); verify(mService, never()).hasScheduleExactAlarmInternal(anyString(), anyInt()); + verify(mService, never()).hasUseExactAlarmInternal(anyString(), anyInt()); verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt()); final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -2520,7 +2551,7 @@ public class AlarmManagerServiceTest { public void binderCallWithUserAllowlist() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - mockExactAlarmPermissionGrant(true, false, MODE_ERRORED); + mockScheduleExactAlarmState(true, false, MODE_ERRORED); when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true); when(mAppStateTracker.isUidPowerSaveUserExempt(TEST_CALLING_UID)).thenReturn(true); @@ -2792,7 +2823,7 @@ public class AlarmManagerServiceTest { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ALLOWED); - mockExactAlarmPermissionGrant(true, false, MODE_ERRORED); + mockScheduleExactAlarmState(true, false, MODE_ERRORED); mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE); assertAndHandleMessageSync(REMOVE_EXACT_ALARMS); @@ -2805,7 +2836,7 @@ public class AlarmManagerServiceTest { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false); mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ALLOWED); - mockExactAlarmPermissionGrant(true, false, MODE_ERRORED); + mockScheduleExactAlarmState(true, false, MODE_ERRORED); mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE); @@ -2818,7 +2849,7 @@ public class AlarmManagerServiceTest { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false); mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ERRORED); - mockExactAlarmPermissionGrant(true, true, MODE_DEFAULT); + mockScheduleExactAlarmState(true, true, MODE_DEFAULT); mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE); @@ -2834,7 +2865,7 @@ public class AlarmManagerServiceTest { when(mActivityManagerInternal.getBootTimeTempAllowListDuration()).thenReturn(durationMs); mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ERRORED); - mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED); + mockScheduleExactAlarmState(true, false, MODE_ALLOWED); mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE); final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); @@ -3036,48 +3067,6 @@ public class AlarmManagerServiceTest { } @Test - public void refreshExactAlarmCandidatesRemovesExactAlarmsIfNeeded() { - mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - - mService.mExactAlarmCandidates = new ArraySet<>(new Integer[]{1, 2, 5}); - final String[] updatedRequesters = new String[]{"p11", "p2", "p9"}; - final Integer[] appIds = new Integer[]{11, 2, 9}; - registerAppIds(updatedRequesters, appIds); - - when(mPermissionManagerInternal.getAppOpPermissionPackages( - SCHEDULE_EXACT_ALARM)).thenReturn(updatedRequesters); - - final PendingIntent exactAppId1 = getNewMockPendingIntent(); - setTestAlarm(ELAPSED_REALTIME, 0, 0, exactAppId1, 0, 0, - UserHandle.getUid(TEST_CALLING_USER, 1), null); - - final PendingIntent exactAppId2 = getNewMockPendingIntent(); - setTestAlarm(ELAPSED_REALTIME, 0, 0, exactAppId2, 0, 0, - UserHandle.getUid(TEST_CALLING_USER, 2), null); - - final PendingIntent exactAppId5 = getNewMockPendingIntent(); - setTestAlarm(ELAPSED_REALTIME, 0, 0, exactAppId5, 0, 0, - UserHandle.getUid(TEST_CALLING_USER, 5), null); - - final PendingIntent inexactAppId5 = getNewMockPendingIntent(); - setTestAlarm(ELAPSED_REALTIME, 0, 23, inexactAppId5, 0, 0, - UserHandle.getUid(TEST_CALLING_USER, 5), null); - - assertEquals(4, mService.mAlarmStore.size()); - - mService.refreshExactAlarmCandidates(); - // App ids 1 and 5 lost the permission, so there alarms should be removed. - - final ArrayList<Alarm> remaining = mService.mAlarmStore.asList(); - assertEquals(2, remaining.size()); - - assertTrue("Inexact alarm removed", - remaining.removeIf(a -> a.matches(inexactAppId5, null))); - assertTrue("Alarm from app id 2 removed", - remaining.removeIf(a -> a.matches(exactAppId2, null))); - } - - @Test public void refreshExactAlarmCandidatesOnPackageAdded() { final String[] exactAlarmRequesters = new String[]{"p11", "p2", "p9"}; final Integer[] appIds = new Integer[]{11, 2, 9}; @@ -3130,6 +3119,78 @@ public class AlarmManagerServiceTest { } @Test + public void exactAlarmsRemovedIfNeededOnPackageReplaced() { + mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); + mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true); + + final int otherUid = 2313; + final String otherPackage = "p1"; + + final PendingIntent exactAlarm1 = getNewMockPendingIntent(); + setTestAlarm(ELAPSED_REALTIME, 1, 0, exactAlarm1, 0, 0, TEST_CALLING_UID, + TEST_CALLING_PACKAGE, null); + + final PendingIntent exactAlarm2 = getNewMockPendingIntent(); + setTestAlarm(ELAPSED_REALTIME, 2, 0, exactAlarm2, 0, 0, TEST_CALLING_UID, + TEST_CALLING_PACKAGE, null); + + final PendingIntent otherPackageExactAlarm = getNewMockPendingIntent(otherUid, + otherPackage); + setTestAlarm(ELAPSED_REALTIME, 0, 0, otherPackageExactAlarm, 0, 0, otherUid, otherPackage, + null); + + final PendingIntent inexactAlarm = getNewMockPendingIntent(); + setTestAlarm(ELAPSED_REALTIME, 0, 23, inexactAlarm, 0, 0, TEST_CALLING_UID, + TEST_CALLING_PACKAGE, null); + + final PendingIntent otherPackageInexactAlarm = getNewMockPendingIntent(otherUid, + otherPackage); + setTestAlarm(ELAPSED_REALTIME, 0, 23, otherPackageInexactAlarm, 0, 0, otherUid, + otherPackage, null); + + assertEquals(5, mService.mAlarmStore.size()); + + final Intent packageReplacedIntent = new Intent(Intent.ACTION_PACKAGE_ADDED) + .setData(Uri.fromParts("package", TEST_CALLING_PACKAGE, null)) + .putExtra(Intent.EXTRA_UID, TEST_CALLING_UID) + .putExtra(Intent.EXTRA_REPLACING, true); + + mockUseExactAlarmState(false); + mockScheduleExactAlarmState(true, false, MODE_ALLOWED); + mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent); + assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE); + + // user permission is granted, no alarms should be removed + assertEquals(5, mService.mAlarmStore.size()); + + mockUseExactAlarmState(true); + mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent); + assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE); + + // policy permission is granted, no alarms should be removed + assertEquals(5, mService.mAlarmStore.size()); + + mockUseExactAlarmState(false); + mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent); + assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE); + + // no permission is granted, exact alarms should be removed + assertEquals(3, mService.mAlarmStore.size()); + + List<Alarm> remaining = mService.mAlarmStore.asList(); + assertTrue("Inexact alarm removed", remaining.removeIf(a -> a.matches(inexactAlarm, null))); + + assertEquals(2, remaining.size()); + assertTrue("Alarms from other package removed", + remaining.removeIf(a -> a.matches(otherPackageExactAlarm, null) + || a.matches(otherPackageInexactAlarm, null))); + + assertEquals(0, remaining.size()); + } + + @Test public void alarmScheduledAtomPushed() { for (int i = 0; i < 10; i++) { final PendingIntent pi = getNewMockPendingIntent(); @@ -3187,6 +3248,28 @@ public class AlarmManagerServiceTest { bOptions.getTemporaryAppAllowlistReasonCode()); } + @Test + public void hasUseExactAlarmPermission() { + mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true); + + mockUseExactAlarmState(true); + assertTrue(mService.hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID)); + + mockUseExactAlarmState(false); + assertFalse(mService.hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID)); + } + + @Test + public void hasUseExactAlarmPermissionChangeDisabled() { + mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, false); + + mockUseExactAlarmState(true); + assertFalse(mService.hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID)); + + mockUseExactAlarmState(false); + assertFalse(mService.hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID)); + } + @After public void tearDown() { if (mMockingSession != null) { diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java index 47d4c8d9af46..32a87b62aeab 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java @@ -579,6 +579,7 @@ public final class BackgroundRestrictionTest { DeviceConfigSession<Boolean> bgPromptFgsWithNotiToBgRestricted = null; DeviceConfigSession<Long> bgNotificationMinInterval = null; DeviceConfigSession<Integer> bgBatteryExemptionTypes = null; + DeviceConfigSession<Boolean> bgCurrentDrainDecoupleThresholds = null; mBgRestrictionController.addAppBackgroundRestrictionListener(listener); @@ -648,6 +649,13 @@ public final class BackgroundRestrictionTest { R.integer.config_bg_current_drain_exempted_types)); bgBatteryExemptionTypes.set(0); + bgCurrentDrainDecoupleThresholds = new DeviceConfigSession<>( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS, + DeviceConfig::getBoolean, + AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD); + bgCurrentDrainDecoupleThresholds.set(true); + mCurrentTimeMillis = 10_000L; doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp(); doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp(); @@ -785,6 +793,11 @@ public final class BackgroundRestrictionTest { anyInt(), anyInt()); }); + // Pretend we have the standby buckets set above. + doReturn(STANDBY_BUCKET_RESTRICTED) + .when(mAppStandbyInternal) + .getAppStandbyBucket(eq(testPkgName), eq(testUser), anyLong(), anyBoolean()); + // Sleep a while and set a higher drain Thread.sleep(windowMs); clearInvocations(mInjector.getAppStandbyInternal()); @@ -921,6 +934,11 @@ public final class BackgroundRestrictionTest { // Expected. } + // Reset the standby bucket. + doReturn(STANDBY_BUCKET_RARE) + .when(mAppStandbyInternal) + .getAppStandbyBucket(eq(testPkgName), eq(testUser), anyLong(), anyBoolean()); + // Turn OFF the FAS. listener.mLatchHolder[0] = new CountDownLatch(1); clearInvocations(mInjector.getAppStandbyInternal()); @@ -930,6 +948,99 @@ public final class BackgroundRestrictionTest { // It'll go back to restricted bucket because it used to behave poorly. listener.verify(timeout, testUid, testPkgName, RESTRICTION_LEVEL_RESTRICTED_BUCKET); verifyRestrictionLevel(RESTRICTION_LEVEL_RESTRICTED_BUCKET, testPkgName, testUid); + + clearInvocations(mInjector.getAppStandbyInternal()); + // Trigger user interaction. + runTestBgCurrentDrainMonitorOnce(listener, stats, uids, + new double[]{restrictBucketThresholdMah - 1, 0}, + new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros, + () -> { + doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp(); + doReturn(mCurrentTimeMillis + windowMs) + .when(stats).getStatsEndTimestamp(); + mCurrentTimeMillis += windowMs + 1; + mIdleStateListener.onUserInteractionStarted(testPkgName, testUser); + waitForIdleHandler(mBgRestrictionController.getBackgroundHandler()); + // It should have been back to normal. + listener.verify(timeout, testUid, testPkgName, + RESTRICTION_LEVEL_ADAPTIVE_BUCKET); + verify(mInjector.getAppStandbyInternal(), atLeast(1)).maybeUnrestrictApp( + eq(testPkgName), + eq(testUser), + eq(REASON_MAIN_USAGE), + eq(REASON_SUB_USAGE_USER_INTERACTION), + eq(REASON_MAIN_USAGE), + eq(REASON_SUB_USAGE_USER_INTERACTION)); + }); + + bgCurrentDrainDecoupleThresholds.set(true); + clearInvocations(mInjector.getAppStandbyInternal()); + + // Go to the threshold right away. + runTestBgCurrentDrainMonitorOnce(listener, stats, uids, + new double[]{0, restrictBucketThresholdMah - 1}, + new double[]{bgRestrictedThresholdMah + 1, 0}, zeros, zeros, + () -> { + doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp(); + doReturn(mCurrentTimeMillis + windowMs) + .when(stats).getStatsEndTimestamp(); + mCurrentTimeMillis += windowMs + 1; + // We won't change restriction level automatically because it needs + // user consent. + try { + listener.verify(timeout, testUid, testPkgName, + RESTRICTION_LEVEL_BACKGROUND_RESTRICTED); + fail("There shouldn't be level change event like this"); + } catch (Exception e) { + // Expected. + } + verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket( + eq(testPkgName), + eq(STANDBY_BUCKET_RARE), + eq(testUser), + anyInt(), anyInt()); + // We should have requested to goto background restricted level. + verify(mBgRestrictionController, times(1)).handleRequestBgRestricted( + eq(testPkgName), + eq(testUid)); + // Verify we have the notification posted now because its FGS is invisible. + checkNotificationShown(new String[] {testPkgName}, atLeast(1), true); + }); + + bgCurrentDrainDecoupleThresholds.set(false); + clearInvocations(mInjector.getAppStandbyInternal()); + clearInvocations(mBgRestrictionController); + + // Go to the threshold right away, but this time, it shouldn't even request to goto + // bg restricted level because it requires to be in restricted bucket before that. + runTestBgCurrentDrainMonitorOnce(listener, stats, uids, + new double[]{0, restrictBucketThresholdMah - 1}, + new double[]{bgRestrictedThresholdMah + 1, 0}, zeros, zeros, + () -> { + doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp(); + doReturn(mCurrentTimeMillis + windowMs) + .when(stats).getStatsEndTimestamp(); + mCurrentTimeMillis += windowMs + 1; + // We won't change restriction level automatically because it needs + // user consent. + try { + listener.verify(timeout, testUid, testPkgName, + RESTRICTION_LEVEL_BACKGROUND_RESTRICTED); + fail("There shouldn't be level change event like this"); + } catch (Exception e) { + // Expected. + } + verify(mInjector.getAppStandbyInternal(), never()).setAppStandbyBucket( + eq(testPkgName), + eq(STANDBY_BUCKET_RARE), + eq(testUser), + anyInt(), anyInt()); + // We should NOT have requested to goto background restricted level. + verify(mBgRestrictionController, never()).handleRequestBgRestricted( + eq(testPkgName), + eq(testUid)); + }); + } finally { closeIfNotNull(bgCurrentDrainMonitor); closeIfNotNull(bgCurrentDrainWindow); @@ -938,6 +1049,7 @@ public final class BackgroundRestrictionTest { closeIfNotNull(bgPromptFgsWithNotiToBgRestricted); closeIfNotNull(bgNotificationMinInterval); closeIfNotNull(bgBatteryExemptionTypes); + closeIfNotNull(bgCurrentDrainDecoupleThresholds); } } @@ -1441,6 +1553,7 @@ public final class BackgroundRestrictionTest { DeviceConfigSession<Boolean> bgPermissionMonitorEnabled = null; DeviceConfigSession<String> bgPermissionsInMonitor = null; DeviceConfigSession<Boolean> bgCurrentDrainHighThresholdByBgLocation = null; + DeviceConfigSession<Boolean> bgCurrentDrainDecoupleThresholds = null; mBgRestrictionController.addAppBackgroundRestrictionListener(listener); @@ -1572,6 +1685,13 @@ public final class BackgroundRestrictionTest { R.bool.config_bg_current_drain_high_threshold_by_bg_location)); bgCurrentDrainHighThresholdByBgLocation.set(true); + bgCurrentDrainDecoupleThresholds = new DeviceConfigSession<>( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLDS, + DeviceConfig::getBoolean, + AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD); + bgCurrentDrainDecoupleThresholds.set(true); + mCurrentTimeMillis = 10_000L; doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp(); doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp(); @@ -1990,6 +2110,7 @@ public final class BackgroundRestrictionTest { closeIfNotNull(bgPermissionMonitorEnabled); closeIfNotNull(bgPermissionsInMonitor); closeIfNotNull(bgCurrentDrainHighThresholdByBgLocation); + closeIfNotNull(bgCurrentDrainDecoupleThresholds); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java index 04fe777cd909..b354c7b3d1f3 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java @@ -116,14 +116,14 @@ public final class JobConcurrencyManagerTest { assertFalse(mJobConcurrencyManager.isPkgConcurrencyLimitedLocked(topJob)); // Pending jobs shouldn't affect TOP job's status. - for (int i = 1; i <= JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) { + for (int i = 1; i <= JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) { final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i); mPendingJobQueue.add(job); } assertFalse(mJobConcurrencyManager.isPkgConcurrencyLimitedLocked(topJob)); // Already running jobs shouldn't affect TOP job's status. - for (int i = 1; i <= JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) { + for (int i = 1; i <= JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) { final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE, i); mJobConcurrencyManager.addRunningJobForTesting(job); } @@ -183,9 +183,9 @@ public final class JobConcurrencyManagerTest { spyOn(testEj); doReturn(true).when(testEj).shouldTreatAsExpeditedJob(); - setConcurrencyConfig(JobSchedulerService.MAX_JOB_CONTEXTS_COUNT); + setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT); - for (int i = 0; i < JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) { + for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) { final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i, i + 1); mPendingJobQueue.add(job); } diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt index 1af6fb7a4027..0567f58b1bbe 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt @@ -203,6 +203,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { val domainVerificationManagerInternal: DomainVerificationManagerInternal = mock() val handler = TestHandler(null) val defaultAppProvider: DefaultAppProvider = mock() + val backgroundHandler = TestHandler(null) } companion object { @@ -286,6 +287,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { .thenReturn(mocks.domainVerificationManagerInternal) whenever(mocks.injector.handler) { mocks.handler } whenever(mocks.injector.defaultAppProvider) { mocks.defaultAppProvider } + whenever(mocks.injector.backgroundHandler) { mocks.backgroundHandler } wheneverStatic { SystemConfig.getInstance() }.thenReturn(mocks.systemConfig) whenever(mocks.systemConfig.availableFeatures).thenReturn(DEFAULT_AVAILABLE_FEATURES_MAP) whenever(mocks.systemConfig.sharedLibraries).thenReturn(DEFAULT_SHARED_LIBRARIES_LIST) diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt index 4818573e9ae5..9774af31950a 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt @@ -17,7 +17,6 @@ package com.android.server.pm import android.content.Intent -import android.content.pm.PackageManagerInternal import android.content.pm.SuspendDialogInfo import android.os.Binder import android.os.Build @@ -27,6 +26,7 @@ import android.os.UserHandle import android.os.UserManager import android.util.ArrayMap import android.util.SparseArray +import com.android.server.pm.KnownPackages import com.android.server.pm.pkg.PackageStateInternal import com.android.server.testutils.TestHandler import com.android.server.testutils.any @@ -484,14 +484,14 @@ class SuspendPackageHelperTest { Mockito.doReturn(DIALER_PACKAGE).`when`(defaultAppProvider) .getDefaultDialer(eq(TEST_USER_ID)) Mockito.doReturn(arrayOf(INSTALLER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal( - any(), eq(PackageManagerInternal.PACKAGE_INSTALLER), eq(TEST_USER_ID)) + any(), eq(KnownPackages.PACKAGE_INSTALLER), eq(TEST_USER_ID)) Mockito.doReturn(arrayOf(UNINSTALLER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal( - any(), eq(PackageManagerInternal.PACKAGE_UNINSTALLER), eq(TEST_USER_ID)) + any(), eq(KnownPackages.PACKAGE_UNINSTALLER), eq(TEST_USER_ID)) Mockito.doReturn(arrayOf(VERIFIER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal( - any(), eq(PackageManagerInternal.PACKAGE_VERIFIER), eq(TEST_USER_ID)) + any(), eq(KnownPackages.PACKAGE_VERIFIER), eq(TEST_USER_ID)) Mockito.doReturn(arrayOf(PERMISSION_CONTROLLER_PACKAGE)).`when`(pms) .getKnownPackageNamesInternal(any(), - eq(PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER), eq(TEST_USER_ID)) + eq(KnownPackages.PACKAGE_PERMISSION_CONTROLLER), eq(TEST_USER_ID)) } private fun createPackageManagerService(vararg stageExistingPackages: String): diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java index 7b921ababf36..c96b4d66f293 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java @@ -40,7 +40,8 @@ import android.app.admin.DevicePolicyManager; import android.companion.AssociationInfo; import android.companion.virtual.IVirtualDeviceActivityListener; import android.companion.virtual.VirtualDeviceParams; -import android.companion.virtual.audio.IAudioSessionCallback; +import android.companion.virtual.audio.IAudioConfigChangedCallback; +import android.companion.virtual.audio.IAudioRoutingCallback; import android.content.Context; import android.content.ContextWrapper; import android.graphics.Point; @@ -115,7 +116,9 @@ public class VirtualDeviceManagerServiceTest { IThermalService mIThermalServiceMock; private PowerManager mPowerManager; @Mock - private IAudioSessionCallback mCallback; + private IAudioRoutingCallback mRoutingCallback; + @Mock + private IAudioConfigChangedCallback mConfigChangedCallback; @Before public void setUp() { @@ -258,7 +261,8 @@ public class VirtualDeviceManagerServiceTest { @Test public void onAudioSessionStarting_noDisplay_failsSecurityException() { assertThrows(SecurityException.class, - () -> mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mCallback)); + () -> mDeviceImpl.onAudioSessionStarting( + DISPLAY_ID, mRoutingCallback, mConfigChangedCallback)); } @Test @@ -300,7 +304,8 @@ public class VirtualDeviceManagerServiceTest { doCallRealMethod().when(mContext).enforceCallingOrSelfPermission( eq(Manifest.permission.CREATE_VIRTUAL_DEVICE), anyString()); assertThrows(SecurityException.class, - () -> mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mCallback)); + () -> mDeviceImpl.onAudioSessionStarting( + DISPLAY_ID, mRoutingCallback, mConfigChangedCallback)); } @Test @@ -347,7 +352,7 @@ public class VirtualDeviceManagerServiceTest { public void onAudioSessionStarting_hasVirtualAudioController() { mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID); - mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mCallback); + mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback); assertThat(mDeviceImpl.getVirtualAudioControllerForTesting()).isNotNull(); } @@ -355,7 +360,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void onAudioSessionEnded_noVirtualAudioController() { mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID); - mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mCallback); + mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback); mDeviceImpl.onAudioSessionEnded(); @@ -365,7 +370,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void close_cleanVirtualAudioController() { mDeviceImpl.onVirtualDisplayCreatedLocked(DISPLAY_ID); - mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mCallback); + mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback); mDeviceImpl.close(); diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java index f0c907d49a46..75faf4554147 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java @@ -26,7 +26,8 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.companion.virtual.VirtualDeviceParams; -import android.companion.virtual.audio.IAudioSessionCallback; +import android.companion.virtual.audio.IAudioConfigChangedCallback; +import android.companion.virtual.audio.IAudioRoutingCallback; import android.content.Context; import android.content.ContextWrapper; import android.media.AudioPlaybackConfiguration; @@ -60,7 +61,10 @@ public class VirtualAudioControllerTest { private Context mContext; private VirtualAudioController mVirtualAudioController; private GenericWindowPolicyController mGenericWindowPolicyController; - @Mock IAudioSessionCallback mCallback; + @Mock + private IAudioRoutingCallback mRoutingCallback; + @Mock + private IAudioConfigChangedCallback mConfigChangedCallback; @Before public void setUp() { @@ -82,42 +86,46 @@ public class VirtualAudioControllerTest { public void startListening_receivesCallback() throws RemoteException { ArraySet<Integer> runningUids = new ArraySet<>(); runningUids.add(APP1_UID); - int[] appUids = new int[] {APP1_UID}; + int[] appUids = new int[]{APP1_UID}; - mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback); + mVirtualAudioController.startListening( + mGenericWindowPolicyController, mRoutingCallback, mConfigChangedCallback); mGenericWindowPolicyController.onRunningAppsChanged(runningUids); - verify(mCallback).onAppsNeedingAudioRoutingChanged(appUids); + verify(mRoutingCallback).onAppsNeedingAudioRoutingChanged(appUids); } @Test public void stopListening_removesCallback() throws RemoteException { ArraySet<Integer> runningUids = new ArraySet<>(); runningUids.add(APP1_UID); - int[] appUids = new int[] {APP1_UID}; - mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback); + int[] appUids = new int[]{APP1_UID}; + mVirtualAudioController.startListening( + mGenericWindowPolicyController, mRoutingCallback, mConfigChangedCallback); mVirtualAudioController.stopListening(); mGenericWindowPolicyController.onRunningAppsChanged(runningUids); - verify(mCallback, never()).onAppsNeedingAudioRoutingChanged(appUids); + verify(mRoutingCallback, never()).onAppsNeedingAudioRoutingChanged(appUids); } @Test public void onRunningAppsChanged_notifiesAudioRoutingModified() throws RemoteException { - mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback); + mVirtualAudioController.startListening( + mGenericWindowPolicyController, mRoutingCallback, mConfigChangedCallback); ArraySet<Integer> runningUids = new ArraySet<>(); runningUids.add(APP1_UID); mVirtualAudioController.onRunningAppsChanged(runningUids); - int[] appUids = new int[] {APP1_UID}; - verify(mCallback).onAppsNeedingAudioRoutingChanged(appUids); + int[] appUids = new int[]{APP1_UID}; + verify(mRoutingCallback).onAppsNeedingAudioRoutingChanged(appUids); } @Test public void onRunningAppsChanged_audioIsPlaying_doesNothing() throws RemoteException { - mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback); + mVirtualAudioController.startListening( + mGenericWindowPolicyController, mRoutingCallback, mConfigChangedCallback); mVirtualAudioController.addPlayingAppsForTesting(APP2_UID); ArraySet<Integer> runningUids = new ArraySet<>(); @@ -125,7 +133,7 @@ public class VirtualAudioControllerTest { mVirtualAudioController.onRunningAppsChanged(runningUids); int[] appUids = new int[]{APP1_UID}; - verify(mCallback, never()).onAppsNeedingAudioRoutingChanged(appUids); + verify(mRoutingCallback, never()).onAppsNeedingAudioRoutingChanged(appUids); } @Test @@ -145,7 +153,8 @@ public class VirtualAudioControllerTest { @Test public void onPlaybackConfigChanged_sendsCallback() throws RemoteException { - mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback); + mVirtualAudioController.startListening( + mGenericWindowPolicyController, mRoutingCallback, mConfigChangedCallback); ArraySet<Integer> runningUids = new ArraySet<>(); runningUids.add(APP1_UID); mVirtualAudioController.onRunningAppsChanged(runningUids); @@ -153,12 +162,13 @@ public class VirtualAudioControllerTest { mVirtualAudioController.onPlaybackConfigChanged(configs); - verify(mCallback).onPlaybackConfigChanged(configs); + verify(mConfigChangedCallback).onPlaybackConfigChanged(configs); } @Test public void onRecordingConfigChanged_sendsCallback() throws RemoteException { - mVirtualAudioController.startListening(mGenericWindowPolicyController, mCallback); + mVirtualAudioController.startListening( + mGenericWindowPolicyController, mRoutingCallback, mConfigChangedCallback); ArraySet<Integer> runningUids = new ArraySet<>(); runningUids.add(APP1_UID); mVirtualAudioController.onRunningAppsChanged(runningUids); @@ -166,7 +176,7 @@ public class VirtualAudioControllerTest { mVirtualAudioController.onRecordingConfigChanged(configs); - verify(mCallback).onRecordingConfigChanged(configs); + verify(mConfigChangedCallback).onRecordingConfigChanged(configs); } private List<AudioPlaybackConfiguration> createPlaybackConfigurations( 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 197c21fad74a..ef7aaca203f7 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -48,6 +48,9 @@ import static android.app.admin.DevicePolicyManager.WIFI_SECURITY_PERSONAL; import static android.app.admin.DevicePolicyManager.WIPE_EUICC; import static android.app.admin.PasswordMetrics.computeForPasswordOrPin; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; +import static android.location.LocationManager.FUSED_PROVIDER; +import static android.location.LocationManager.GPS_PROVIDER; +import static android.location.LocationManager.NETWORK_PROVIDER; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK; @@ -8462,34 +8465,44 @@ public class DevicePolicyManagerTest extends DpmTestBase { @Test public void testSendLostModeLocationUpdate_asDeviceOwner() throws Exception { - final String TEST_PROVIDER = "network"; mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE); setDeviceOwner(); - when(getServices().locationManager.getAllProviders()).thenReturn(List.of(TEST_PROVIDER)); - when(getServices().locationManager.isProviderEnabled(TEST_PROVIDER)).thenReturn(true); + when(getServices().locationManager.isProviderEnabled(FUSED_PROVIDER)).thenReturn(true); dpm.sendLostModeLocationUpdate(getServices().executor, /* empty callback */ result -> {}); verify(getServices().locationManager, times(1)).getCurrentLocation( - eq(TEST_PROVIDER), any(), eq(getServices().executor), any()); + eq(FUSED_PROVIDER), any(), eq(getServices().executor), any()); } @Test public void testSendLostModeLocationUpdate_asProfileOwnerOfOrgOwnedDevice() throws Exception { - final String TEST_PROVIDER = "network"; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE); addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE); - when(getServices().locationManager.getAllProviders()).thenReturn(List.of(TEST_PROVIDER)); - when(getServices().locationManager.isProviderEnabled(TEST_PROVIDER)).thenReturn(true); + when(getServices().locationManager.isProviderEnabled(FUSED_PROVIDER)).thenReturn(true); dpm.sendLostModeLocationUpdate(getServices().executor, /* empty callback */ result -> {}); verify(getServices().locationManager, times(1)).getCurrentLocation( - eq(TEST_PROVIDER), any(), eq(getServices().executor), any()); + eq(FUSED_PROVIDER), any(), eq(getServices().executor), any()); + } + + @Test + public void testSendLostModeLocationUpdate_noProviderIsEnabled() throws Exception { + mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE); + setDeviceOwner(); + when(getServices().locationManager.isProviderEnabled(FUSED_PROVIDER)).thenReturn(false); + when(getServices().locationManager.isProviderEnabled(NETWORK_PROVIDER)).thenReturn(false); + when(getServices().locationManager.isProviderEnabled(GPS_PROVIDER)).thenReturn(false); + + dpm.sendLostModeLocationUpdate(getServices().executor, /* empty callback */ result -> {}); + + verify(getServices().locationManager, never()).getCurrentLocation( + eq(FUSED_PROVIDER), any(), eq(getServices().executor), any()); } private void setupVpnAuthorization(String userVpnPackage, int userVpnUid) { diff --git a/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java b/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java index bda7cf66f685..e886e7dc1d60 100644 --- a/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java +++ b/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java @@ -57,14 +57,14 @@ public class BiasSchedulingTest extends AndroidTestCase { } public void testLowerBiasJobPreempted() throws Exception { - for (int i = 0; i < JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) { + for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) { JobInfo job = new JobInfo.Builder(100 + i, sJobServiceComponent) .setBias(LOW_BIAS) .setOverrideDeadline(0) .build(); mJobScheduler.schedule(job); } - final int higherBiasJobId = 100 + JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; + final int higherBiasJobId = 100 + JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; JobInfo jobHigher = new JobInfo.Builder(higherBiasJobId, sJobServiceComponent) .setBias(HIGH_BIAS) .setMinimumLatency(2000) @@ -88,14 +88,14 @@ public class BiasSchedulingTest extends AndroidTestCase { } public void testHigherBiasJobNotPreempted() throws Exception { - for (int i = 0; i < JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) { + for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) { JobInfo job = new JobInfo.Builder(100 + i, sJobServiceComponent) .setBias(HIGH_BIAS) .setOverrideDeadline(0) .build(); mJobScheduler.schedule(job); } - final int lowerBiasJobId = 100 + JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; + final int lowerBiasJobId = 100 + JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; JobInfo jobLower = new JobInfo.Builder(lowerBiasJobId, sJobServiceComponent) .setBias(LOW_BIAS) .setMinimumLatency(2000) diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java index 2b33088dd678..1877d45e5ce3 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java @@ -189,8 +189,8 @@ public class PackageManagerServiceTest { @Test public void testKnownPackageToString_shouldNotGetUnknown() { final List<String> packageNames = new ArrayList<>(); - for (int i = 0; i <= PackageManagerInternal.LAST_KNOWN_PACKAGE; i++) { - packageNames.add(PackageManagerInternal.knownPackageToString(i)); + for (int i = 0; i <= KnownPackages.LAST_KNOWN_PACKAGE; i++) { + packageNames.add(KnownPackages.knownPackageToString(i)); } assertWithMessage( "The Ids of KnownPackage should be continuous and the string representation " @@ -205,7 +205,7 @@ public class PackageManagerServiceTest { "The last KnownPackage Id should be assigned to PackageManagerInternal" + ".LAST_KNOWN_PACKAGE.").that( knownPackageIds.get(knownPackageIds.size() - 1)).isEqualTo( - PackageManagerInternal.LAST_KNOWN_PACKAGE); + KnownPackages.LAST_KNOWN_PACKAGE); } @Test @@ -470,7 +470,7 @@ public class PackageManagerServiceTest { private List<Integer> getKnownPackageIdsList() throws IllegalAccessException { final ArrayList<Integer> knownPackageIds = new ArrayList<>(); - final Field[] allFields = PackageManagerInternal.class.getDeclaredFields(); + final Field[] allFields = KnownPackages.class.getDeclaredFields(); for (Field field : allFields) { final int modifier = field.getModifiers(); if (isPublic(modifier) && isStatic(modifier) && isFinal(modifier) diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java index 17464a6551d4..fb4d84cc75f2 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -283,7 +283,7 @@ public class AppStandbyControllerTests { } @Override - boolean hasScheduleExactAlarm(String packageName, int uid) { + boolean hasExactAlarmPermission(String packageName, int uid) { return mClockApps.contains(Pair.create(packageName, uid)); } diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java index 27b254a304ff..e8c989280a0e 100644 --- a/services/translation/java/com/android/server/translation/TranslationManagerService.java +++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java @@ -225,12 +225,12 @@ public final class TranslationManagerService @Override public void registerUiTranslationStateCallback(IRemoteCallback callback, int userId) { - TranslationManagerServiceImpl service; synchronized (mLock) { - service = getServiceForUserLocked(userId); - } - if (service != null) { - service.registerUiTranslationStateCallback(callback, Binder.getCallingUid()); + final TranslationManagerServiceImpl service = getServiceForUserLocked(userId); + if (service != null) { + service.registerUiTranslationStateCallbackLocked(callback, + Binder.getCallingUid()); + } } } @@ -297,7 +297,7 @@ public final class TranslationManagerService /** * Dump the service state into the given stream. You run "adb shell dumpsys translation". - */ + */ @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java index 3833ceb3122e..d3a589668808 100644 --- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java +++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java @@ -22,9 +22,13 @@ import static android.view.translation.UiTranslationManager.EXTRA_SOURCE_LOCALE; import static android.view.translation.UiTranslationManager.EXTRA_STATE; import static android.view.translation.UiTranslationManager.EXTRA_TARGET_LOCALE; import static android.view.translation.UiTranslationManager.STATE_UI_TRANSLATION_FINISHED; +import static android.view.translation.UiTranslationManager.STATE_UI_TRANSLATION_PAUSED; +import static android.view.translation.UiTranslationManager.STATE_UI_TRANSLATION_RESUMED; +import static android.view.translation.UiTranslationManager.STATE_UI_TRANSLATION_STARTED; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.ComponentName; import android.content.Context; @@ -38,7 +42,9 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.service.translation.TranslationServiceInfo; import android.util.ArraySet; +import android.util.Log; import android.util.Slog; +import android.util.SparseArray; import android.view.autofill.AutofillId; import android.view.inputmethod.InputMethodInfo; import android.view.translation.ITranslationServiceCallback; @@ -68,6 +74,8 @@ final class TranslationManagerServiceImpl extends AbstractPerUserSystemService<TranslationManagerServiceImpl, TranslationManagerService> { private static final String TAG = "TranslationManagerServiceImpl"; + @SuppressLint("IsLoggableTagLength") + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @GuardedBy("mLock") @Nullable @@ -83,13 +91,19 @@ final class TranslationManagerServiceImpl extends @GuardedBy("mLock") private WeakReference<ActivityTokens> mLastActivityTokens; - private ActivityTaskManagerInternal mActivityTaskManagerInternal; + private final ActivityTaskManagerInternal mActivityTaskManagerInternal; private final TranslationServiceRemoteCallback mRemoteServiceCallback = new TranslationServiceRemoteCallback(); private final RemoteCallbackList<IRemoteCallback> mTranslationCapabilityCallbacks = new RemoteCallbackList<>(); - private final ArraySet<IBinder> mWaitingFinishedCallbackActivities = new ArraySet(); + private final ArraySet<IBinder> mWaitingFinishedCallbackActivities = new ArraySet<>(); + + /** + * Key is translated activity uid, value is the specification and state for the translation. + */ + @GuardedBy("mLock") + private final SparseArray<ActiveTranslation> mActiveTranslations = new SparseArray<>(); protected TranslationManagerServiceImpl( @NonNull TranslationManagerService master, @@ -231,6 +245,7 @@ final class TranslationManagerServiceImpl extends if (state == STATE_UI_TRANSLATION_FINISHED) { mWaitingFinishedCallbackActivities.add(token); } + IBinder activityToken = taskTopActivityTokens.getActivityToken(); try { taskTopActivityTokens.getApplicationThread().updateUiTranslationState( @@ -243,9 +258,46 @@ final class TranslationManagerServiceImpl extends ComponentName componentName = mActivityTaskManagerInternal.getActivityName(activityToken); int translationActivityUid = getActivityUidByComponentName(getContext(), componentName, getUserId()); + String packageName = componentName.getPackageName(); if (state != STATE_UI_TRANSLATION_FINISHED) { - invokeCallbacks(state, sourceSpec, targetSpec, componentName.getPackageName(), + invokeCallbacks(state, sourceSpec, targetSpec, packageName, translationActivityUid); + updateActiveTranslations(state, sourceSpec, targetSpec, packageName, translationActivityUid); + } else { + if (mActiveTranslations.contains(translationActivityUid)) { + mActiveTranslations.delete(translationActivityUid); + } else { + Slog.w(TAG, "Finishing translation for activity with uid=" + translationActivityUid + + " but no active translation was found for it"); + } + } + } + + @GuardedBy("mLock") + private void updateActiveTranslations(int state, TranslationSpec sourceSpec, + TranslationSpec targetSpec, String packageName, int translationActivityUid) { + // Keep track of active translations so that we can trigger callbacks that are + // registered after translation has started. + switch (state) { + case STATE_UI_TRANSLATION_STARTED: { + ActiveTranslation activeTranslation = new ActiveTranslation(sourceSpec, + targetSpec, packageName); + mActiveTranslations.put(translationActivityUid, activeTranslation); + break; + } + case STATE_UI_TRANSLATION_PAUSED: + case STATE_UI_TRANSLATION_RESUMED: { + ActiveTranslation activeTranslation = mActiveTranslations.get( + translationActivityUid); + if (activeTranslation != null) { + activeTranslation.isPaused = (state == STATE_UI_TRANSLATION_PAUSED); + } else { + Slog.w(TAG, "Pausing or resuming translation for activity with uid=" + + translationActivityUid + + " but no active translation was found for it"); + } + break; + } } } @@ -289,49 +341,105 @@ final class TranslationManagerServiceImpl extends private void invokeCallbacks( int state, TranslationSpec sourceSpec, TranslationSpec targetSpec, String packageName, int translationActivityUid) { - Bundle res = new Bundle(); - res.putInt(EXTRA_STATE, state); + Bundle result = createResultForCallback(state, sourceSpec, targetSpec, packageName); + if (mCallbacks.getRegisteredCallbackCount() == 0) { + return; + } + List<InputMethodInfo> enabledInputMethods = getEnabledInputMethods(); + mCallbacks.broadcast((callback, uid) -> { + invokeCallback((int) uid, translationActivityUid, callback, result, + enabledInputMethods); + }); + } + + private List<InputMethodInfo> getEnabledInputMethods() { + return LocalServices.getService(InputMethodManagerInternal.class) + .getEnabledInputMethodListAsUser(mUserId); + } + + private Bundle createResultForCallback( + int state, TranslationSpec sourceSpec, TranslationSpec targetSpec, String packageName) { + Bundle result = new Bundle(); + result.putInt(EXTRA_STATE, state); // TODO(177500482): Store the locale pair so it can be sent for RESUME events. if (sourceSpec != null) { - res.putSerializable(EXTRA_SOURCE_LOCALE, sourceSpec.getLocale()); - res.putSerializable(EXTRA_TARGET_LOCALE, targetSpec.getLocale()); + result.putSerializable(EXTRA_SOURCE_LOCALE, sourceSpec.getLocale()); + result.putSerializable(EXTRA_TARGET_LOCALE, targetSpec.getLocale()); } - res.putString(EXTRA_PACKAGE_NAME, packageName); - // TODO(177500482): Only support the *current* Input Method. - List<InputMethodInfo> enabledInputMethods = - LocalServices.getService(InputMethodManagerInternal.class) - .getEnabledInputMethodListAsUser(mUserId); - mCallbacks.broadcast((callback, uid) -> { - if ((int) uid == translationActivityUid) { - try { - callback.sendResult(res); - } catch (RemoteException e) { - Slog.w(TAG, "Failed to invoke UiTranslationStateCallback: " + e); - } - return; - } - // Code here is non-optimal since it's temporary.. - boolean isIme = false; - for (InputMethodInfo inputMethod : enabledInputMethods) { - if ((int) uid == inputMethod.getServiceInfo().applicationInfo.uid) { - isIme = true; - } - } - // TODO(177500482): Invoke it for the application being translated too. - if (!isIme) { - return; - } + result.putString(EXTRA_PACKAGE_NAME, packageName); + return result; + } + + private void invokeCallback( + int callbackSourceUid, int translationActivityUid, IRemoteCallback callback, + Bundle result, List<InputMethodInfo> enabledInputMethods) { + if (callbackSourceUid == translationActivityUid) { + // Invoke callback for the application being translated. try { - callback.sendResult(res); + callback.sendResult(result); } catch (RemoteException e) { Slog.w(TAG, "Failed to invoke UiTranslationStateCallback: " + e); } - }); + return; + } + + // TODO(177500482): Only support the *current* Input Method. + // Code here is non-optimal since it's temporary.. + boolean isIme = false; + for (InputMethodInfo inputMethod : enabledInputMethods) { + if (callbackSourceUid == inputMethod.getServiceInfo().applicationInfo.uid) { + isIme = true; + break; + } + } + + if (!isIme) { + return; + } + try { + callback.sendResult(result); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to invoke UiTranslationStateCallback: " + e); + } } - public void registerUiTranslationStateCallback(IRemoteCallback callback, int sourceUid) { + @GuardedBy("mLock") + public void registerUiTranslationStateCallbackLocked(IRemoteCallback callback, int sourceUid) { mCallbacks.register(callback, sourceUid); - // TODO(177500482): trigger the callback here if we're already translating the UI. + + if (mActiveTranslations.size() == 0) { + return; + } + + // Trigger the callback for already active translations. + List<InputMethodInfo> enabledInputMethods = getEnabledInputMethods(); + for (int i = 0; i < mActiveTranslations.size(); i++) { + int activeTranslationUid = mActiveTranslations.keyAt(i); + ActiveTranslation activeTranslation = mActiveTranslations.valueAt(i); + if (activeTranslation == null) { + continue; + } + String packageName = activeTranslation.packageName; + if (DEBUG) { + Slog.d(TAG, "Triggering callback for sourceUid=" + sourceUid + + " for translated activity with uid=" + activeTranslationUid + + "packageName=" + packageName + " isPaused=" + activeTranslation.isPaused); + } + + Bundle startedResult = createResultForCallback(STATE_UI_TRANSLATION_STARTED, + activeTranslation.sourceSpec, activeTranslation.targetSpec, + packageName); + invokeCallback(sourceUid, activeTranslationUid, callback, startedResult, + enabledInputMethods); + if (activeTranslation.isPaused) { + // Also send event so callback owners know that translation was started then paused. + Bundle pausedResult = createResultForCallback(STATE_UI_TRANSLATION_PAUSED, + activeTranslation.sourceSpec, activeTranslation.targetSpec, + packageName); + invokeCallback(sourceUid, activeTranslationUid, callback, pausedResult, + enabledInputMethods); + } + } } public void unregisterUiTranslationStateCallback(IRemoteCallback callback) { @@ -376,4 +484,18 @@ final class TranslationManagerServiceImpl extends notifyClientsTranslationCapability(capability); } } + + private static final class ActiveTranslation { + public final TranslationSpec sourceSpec; + public final TranslationSpec targetSpec; + public final String packageName; + public boolean isPaused = false; + + private ActiveTranslation(TranslationSpec sourceSpec, TranslationSpec targetSpec, + String packageName) { + this.sourceSpec = sourceSpec; + this.targetSpec = targetSpec; + this.packageName = packageName; + } + } } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 8880bc492de7..8d7fab4d101f 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -4379,12 +4379,14 @@ public class CarrierConfigManager { * The data stall recovery timers array in milliseconds, each element is the delay before * performining next recovery action. * - * The default value of timers array are: [180000ms, 180000ms, 180000ms] (3 minutes) + * The default value of timers array are: [180000ms, 180000ms, 180000ms, 180000ms] (3 minutes) * Array[0]: It's the timer between RECOVERY_ACTION GET_DATA_CALL_LIST and CLEANUP, if data * stall symptom still occurred, it will perform next recovery action after 180000ms. - * Array[1]: It's the timer between RECOVERY_ACTION CLEANUP and RADIO_RESTART, if data stall + * Array[1]: It's the timer between RECOVERY_ACTION CLEANUP and RE-REGISTER, if data stall * symptom still occurred, it will perform next recovery action after 180000ms. - * Array[2]: It's the timer between RECOVERY_ACTION RADIO_RESTART and RESET_MODEM, if data stall + * Array[2]: It's the timer between RECOVERY_ACTION RE-REGISTER and RADIO_RESTART, if data stall + * symptom still occurred, it will perform next recovery action after 180000ms. + * Array[3]: It's the timer between RECOVERY_ACTION RADIO_RESTART and RESET_MODEM, if data stall * symptom still occurred, it will perform next recovery action after 180000ms. * * See the {@code RECOVERY_ACTION_*} constants in @@ -4404,7 +4406,7 @@ public class CarrierConfigManager { * RECOVERY_ACTION_CLEANUP to true, then it can be ignored to speed up the recovery * action procedure. * - * The default value of boolean array are: [false, false, false, false] + * The default value of boolean array are: [false, false, true, false, false] * Array[0]: When performing the recovery action, we can use this boolean value to determine * if we need to perform RECOVERY_ACTION_GET_DATA_CALL_LIST. * Array[1]: If data stall symptom still occurred, we can use this boolean value to determine @@ -4414,8 +4416,10 @@ public class CarrierConfigManager { * variable of action RECOVERY_ACTION_CLEANUP to true, then it can be ignored to speed up the * recovery action procedure. * Array[2]: If data stall symptom still occurred, we can use this boolean value to determine - * if we need to perform RECOVERY_ACTION_RADIO_RESTART. + * if we need to perform RE-REGISTER. * Array[3]: If data stall symptom still occurred, we can use this boolean value to determine + * if we need to perform RECOVERY_ACTION_RADIO_RESTART. + * Array[4]: If data stall symptom still occurred, we can use this boolean value to determine * if we need to perform RECOVERY_ACTION_MODEM_RESET. * * See the {@code RECOVERY_ACTION_*} constants in @@ -9159,9 +9163,9 @@ public class CarrierConfigManager { SubscriptionManager.USAGE_SETTING_UNKNOWN); // Default data stall recovery configurations. sDefaults.putLongArray(KEY_DATA_STALL_RECOVERY_TIMERS_LONG_ARRAY, - new long[] {180000, 180000, 180000}); + new long[] {180000, 180000, 180000, 180000}); sDefaults.putBooleanArray(KEY_DATA_STALL_RECOVERY_SHOULD_SKIP_BOOL_ARRAY, - new boolean[] {false, false, false, false}); + new boolean[] {false, false, true, false, false}); } /** diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index fc9acb81d408..7c7bf0a21c3f 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -3216,6 +3216,11 @@ public class SubscriptionManager { * * @param subId sub id * @param callbackIntent pending intent that will be sent after operation is done. + * + * to-be-deprecated this API is a duplicate of {@link EuiccManager#switchToSubscription(int, + * PendingIntent)} and does not support Multiple Enabled Profile(MEP). Apps should use + * {@link EuiccManager#switchToSubscription(int, PendingIntent)} or + * {@link EuiccManager#switchToSubscription(int, int, PendingIntent)} instead. */ @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void switchToSubscription(int subId, @NonNull PendingIntent callbackIntent) { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt index a425ee0ed969..d1319ac095ed 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt @@ -17,7 +17,6 @@ package com.android.server.wm.flicker.close -import android.platform.test.annotations.Presubmit import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory @@ -99,38 +98,6 @@ class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio super.statusBarLayerRotatesScales() } - /** {@inheritDoc} */ - @Presubmit - @Test - override fun launcherLayerReplacesApp() { - // This test doesn't work in shell transitions because of b/206086894 - assumeFalse(isShellTransitionsEnabled) - super.launcherLayerReplacesApp() - } - - @FlakyTest(bugId = 214452854) - @Test - fun launcherLayerReplacesApp_shellTransit() { - assumeTrue(isShellTransitionsEnabled) - super.launcherLayerReplacesApp() - } - - /** {@inheritDoc} */ - @Presubmit - @Test - override fun entireScreenCovered() { - // This test doesn't work in shell transitions because of b/206086894 - assumeFalse(isShellTransitionsEnabled) - super.entireScreenCovered() - } - - @FlakyTest(bugId = 214452854) - @Test - fun entireScreenCovered_shellTransit() { - assumeTrue(isShellTransitionsEnabled) - super.entireScreenCovered() - } - companion object { /** * Creates the test configurations. diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt index a0892612f4e4..f5fb10611d6b 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt @@ -24,9 +24,6 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import org.junit.Assume.assumeFalse -import org.junit.Assume.assumeTrue import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -83,18 +80,9 @@ class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales() /** {@inheritDoc} */ - @FlakyTest(bugId = 206753786) + @FlakyTest(bugId = 227430489) @Test override fun statusBarLayerRotatesScales() { - // This test doesn't work in shell transitions because of b/206753786 - assumeFalse(isShellTransitionsEnabled) - super.statusBarLayerRotatesScales() - } - - @FlakyTest(bugId = 214452854) - @Test - fun statusBarLayerRotatesScales_shellTransit() { - assumeTrue(isShellTransitionsEnabled) super.statusBarLayerRotatesScales() } @@ -102,15 +90,6 @@ class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio @Presubmit @Test override fun launcherLayerReplacesApp() { - // This test doesn't work in shell transitions because of b/206086894 - assumeFalse(isShellTransitionsEnabled) - super.launcherLayerReplacesApp() - } - - @FlakyTest(bugId = 214452854) - @Test - fun launcherLayerReplacesApp_shellTransit() { - assumeTrue(isShellTransitionsEnabled) super.launcherLayerReplacesApp() } @@ -118,15 +97,6 @@ class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio @Presubmit @Test override fun entireScreenCovered() { - // This test doesn't work in shell transitions because of b/206086894 - assumeFalse(isShellTransitionsEnabled) - super.entireScreenCovered() - } - - @FlakyTest(bugId = 214452854) - @Test - fun entireScreenCovered_shellTransit() { - assumeTrue(isShellTransitionsEnabled) super.entireScreenCovered() } @@ -134,15 +104,6 @@ class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio @Presubmit @Test override fun visibleLayersShownMoreThanOneConsecutiveEntry() { - // This test doesn't work in shell transitions because of b/215885246 - assumeFalse(isShellTransitionsEnabled) - super.visibleLayersShownMoreThanOneConsecutiveEntry() - } - - @FlakyTest(bugId = 214452854) - @Test - fun visibleLayersShownMoreThanOneConsecutiveEntry_shellTransit() { - assumeTrue(isShellTransitionsEnabled) super.visibleLayersShownMoreThanOneConsecutiveEntry() } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt index f8348203599f..2f6b8f008119 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt @@ -24,11 +24,8 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome -import org.junit.Assume -import org.junit.Before import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -59,11 +56,6 @@ import org.junit.runners.Parameterized @Group1 open class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppFromLauncherTransition(testSpec) { - @Before - open fun before() { - Assume.assumeFalse(isShellTransitionsEnabled) - } - /** * Defines the transition used to run the test */ @@ -121,7 +113,7 @@ open class OpenAppColdTest(testSpec: FlickerTestParameter) override fun navBarWindowIsVisible() = super.navBarWindowIsVisible() /** {@inheritDoc} */ - @FlakyTest(bugId = 213852103) + @Presubmit @Test override fun entireScreenCovered() = super.entireScreenCovered() diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest_ShellTransit.kt deleted file mode 100644 index 0d2869cbd178..000000000000 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest_ShellTransit.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm.flicker.launch - -import androidx.test.filters.FlakyTest -import android.platform.test.annotations.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.annotation.Group1 -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import org.junit.Assume -import org.junit.Before -import org.junit.FixMethodOrder -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test cold launching an app from launcher - * - * To run this test: `atest FlickerTests:OpenAppColdTest` - * - * Actions: - * Make sure no apps are running on the device - * Launch an app [testApp] and wait animation to complete - * - * Notes: - * 1. Some default assertions (e.g., nav bar, status bar and screen covered) - * are inherited [OpenAppTransition] - * 2. Part of the test setup occurs automatically via - * [com.android.server.wm.flicker.TransitionRunnerWithRules], - * including configuring navigation mode, initial orientation and ensuring no - * apps are running before setup - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group1 -@FlakyTest(bugId = 219688533) -class OpenAppColdTest_ShellTransit(testSpec: FlickerTestParameter) : OpenAppColdTest(testSpec) { - @Before - override fun before() { - Assume.assumeTrue(isShellTransitionsEnabled) - } -} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt index 00fee82adf76..ee0f3d8cd945 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt @@ -135,7 +135,7 @@ open class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) override fun appLayerBecomesVisible() = super.appLayerBecomesVisible_warmStart() /** {@inheritDoc} */ - @FlakyTest(bugId = 218624176) + @Presubmit @Test override fun appWindowBecomesVisible() = super.appWindowBecomesVisible_warmStart() diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt index 1c06495cf473..55e1e9ba8557 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt @@ -54,7 +54,6 @@ import org.junit.runners.Parameterized @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @Group1 -@FlakyTest(bugId = 219688533) class OpenAppFromOverviewTest_ShellTransit(testSpec: FlickerTestParameter) : OpenAppFromOverviewTest(testSpec) { @Before @@ -65,6 +64,11 @@ class OpenAppFromOverviewTest_ShellTransit(testSpec: FlickerTestParameter) /** {@inheritDoc} */ @FlakyTest(bugId = 216266712) @Test + override fun appWindowBecomesTopWindow() = super.appWindowBecomesTopWindow() + + /** {@inheritDoc} */ + @FlakyTest(bugId = 216266712) + @Test override fun appWindowReplacesLauncherAsTopWindow() = super.appWindowReplacesLauncherAsTopWindow() diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt index f700416e4269..fbd611a37d0a 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt @@ -17,7 +17,6 @@ package com.android.server.wm.flicker.launch import androidx.test.filters.FlakyTest -import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit import android.platform.test.annotations.RequiresDevice import android.view.Surface @@ -99,7 +98,7 @@ open class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) * Checks that the nav bar starts the transition invisible, then becomes visible during * the unlocking animation and remains visible at the end of the transition */ - @Postsubmit + @Presubmit @Test fun navBarWindowsVisibilityChanges() { testSpec.assertWm { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt index 2562098a10ff..48f6aeb4d824 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt @@ -24,10 +24,7 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.helpers.setRotation -import org.junit.Assume -import org.junit.Before import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -59,11 +56,6 @@ import org.junit.runners.Parameterized @Group1 open class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppFromLauncherTransition(testSpec) { - @Before - open fun before() { - Assume.assumeFalse(isShellTransitionsEnabled) - } - /** * Defines the transition used to run the test */ diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest_ShellTransit.kt deleted file mode 100644 index 3958dd2c89b4..000000000000 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest_ShellTransit.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm.flicker.launch - -import androidx.test.filters.FlakyTest -import android.platform.test.annotations.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.annotation.Group1 -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import org.junit.Assume -import org.junit.Before -import org.junit.FixMethodOrder -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test warm launching an app from launcher - * - * To run this test: `atest FlickerTests:OpenAppWarmTest` - * - * Actions: - * Launch [testApp] - * Press home - * Relaunch an app [testApp] and wait animation to complete (only this action is traced) - * - * Notes: - * 1. Some default assertions (e.g., nav bar, status bar and screen covered) - * are inherited [OpenAppTransition] - * 2. Part of the test setup occurs automatically via - * [com.android.server.wm.flicker.TransitionRunnerWithRules], - * including configuring navigation mode, initial orientation and ensuring no - * apps are running before setup - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group1 -@FlakyTest(bugId = 219688533) -class OpenAppWarmTest_ShellTransit(testSpec: FlickerTestParameter) - : OpenAppWarmTest(testSpec) { - @Before - override fun before() { - Assume.assumeTrue(isShellTransitionsEnabled) - } -} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt index c89e6a44ab6c..1eb3d8da9f1e 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt @@ -33,15 +33,12 @@ import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.NonResizeableAppHelper import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.helpers.WindowUtils -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.navBarLayerIsVisible import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarWindowIsVisible import com.android.server.wm.traces.common.FlickerComponentName -import org.junit.Assume -import org.junit.Before import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -73,11 +70,6 @@ open class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestPa private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation) - @Before - open fun before() { - Assume.assumeFalse(isShellTransitionsEnabled) - } - @FlickerBuilderProvider fun buildFlicker(): FlickerBuilder { return FlickerBuilder(instrumentation).apply { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt deleted file mode 100644 index cffed81f6cb9..000000000000 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm.flicker.quickswitch - -import androidx.test.filters.FlakyTest -import android.platform.test.annotations.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.annotation.Group1 -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import org.junit.Assume -import org.junit.Before -import org.junit.FixMethodOrder -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test quick switching back to previous app from last opened app - * - * To run this test: `atest FlickerTests:QuickSwitchBetweenTwoAppsBackTest` - * - * Actions: - * Launch an app [testApp1] - * Launch another app [testApp2] - * Swipe right from the bottom of the screen to quick switch back to the first app [testApp1] - * - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group1 -@FlakyTest(bugId = 219690120) -class QuickSwitchBetweenTwoAppsBackTest_ShellTransit(testSpec: FlickerTestParameter) - : QuickSwitchBetweenTwoAppsBackTest(testSpec) { - @Before - override fun before() { - Assume.assumeTrue(isShellTransitionsEnabled) - } -} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt index b449dd227ad3..5474a42ccf52 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt @@ -32,7 +32,6 @@ import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.NonResizeableAppHelper import com.android.server.wm.flicker.helpers.SimpleAppHelper -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled import com.android.server.wm.flicker.navBarLayerIsVisible import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.navBarWindowIsVisible @@ -40,8 +39,6 @@ import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarWindowIsVisible import com.android.server.wm.traces.common.FlickerComponentName import com.android.server.wm.traces.common.Rect -import org.junit.Assume -import org.junit.Before import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -114,12 +111,6 @@ open class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTes } } - @Before - open fun setup() { - // This test doesn't work in shell transitions because of b/213867585 - Assume.assumeFalse(isShellTransitionsEnabled) - } - /** * Checks that the transition starts with [testApp1]'s windows filling/covering exactly the * entirety of the display. diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestShellTransit.kt deleted file mode 100644 index 49b973390e7c..000000000000 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestShellTransit.kt +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm.flicker.quickswitch - -import android.platform.test.annotations.RequiresDevice -import androidx.test.filters.FlakyTest -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.annotation.Group1 -import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled -import org.junit.Assume -import org.junit.Before -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test quick switching back to previous app from last opened app - * - * To run this test: `atest FlickerTests:QuickSwitchBetweenTwoAppsForwardTestShellTransit` - * - * Actions: - * Launch an app [testApp1] - * Launch another app [testApp2] - * Swipe right from the bottom of the screen to quick switch back to the first app [testApp1] - * Swipe left from the bottom of the screen to quick switch forward to the second app [testApp2] - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group1 -class QuickSwitchBetweenTwoAppsForwardTestShellTransit(private val testSpec: FlickerTestParameter) - : QuickSwitchBetweenTwoAppsForwardTest(testSpec) { - - @Before - override fun setup() { - // This test class should be removed after b/213867585 is fixed. - Assume.assumeTrue(isShellTransitionsEnabled) - } - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun startsWithApp1WindowsCoverFullScreen() = - super.startsWithApp1WindowsCoverFullScreen() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun startsWithApp1LayersCoverFullScreen() = super.startsWithApp1LayersCoverFullScreen() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun startsWithApp1WindowBeingOnTop() = super.startsWithApp1WindowBeingOnTop() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun endsWithApp2WindowsCoveringFullScreen() = - super.endsWithApp2WindowsCoveringFullScreen() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun endsWithApp2LayersCoveringFullScreen() = - super.endsWithApp2LayersCoveringFullScreen() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun endsWithApp2BeingOnTop() = super.endsWithApp2BeingOnTop() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun app2WindowBecomesAndStaysVisible() = super.app2WindowBecomesAndStaysVisible() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun app2LayerBecomesAndStaysVisible() = super.app2LayerBecomesAndStaysVisible() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun app1WindowBecomesAndStaysInvisible() = super.app1WindowBecomesAndStaysInvisible() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun app1LayerBecomesAndStaysInvisible() = super.app1LayerBecomesAndStaysInvisible() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun app2WindowIsVisibleOnceApp1WindowIsInvisible() = - super.app2WindowIsVisibleOnceApp1WindowIsInvisible() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun app2LayerIsVisibleOnceApp1LayerIsInvisible() = - super.app2LayerIsVisibleOnceApp1LayerIsInvisible() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun navBarLayerAlwaysIsVisible() = super.navBarLayerAlwaysIsVisible() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun navbarIsAlwaysInRightPosition() = super.navbarIsAlwaysInRightPosition() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible() - - /** {@inheritDoc} */ - @FlakyTest(bugId = 214452854) - @Test - override fun statusBarLayerIsAlwaysVisible() = super.statusBarLayerIsAlwaysVisible() -}
\ No newline at end of file |