diff options
349 files changed, 8734 insertions, 3830 deletions
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 2b0a833e1d1f..ee0f9e8f9658 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 @@ -37,7 +37,6 @@ import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AlarmManager; import android.app.IUidObserver; -import android.app.job.JobInfo; import android.app.usage.UsageEvents; import android.app.usage.UsageStatsManagerInternal; import android.app.usage.UsageStatsManagerInternal.UsageEventListener; @@ -166,28 +165,6 @@ public final class QuotaController extends StateController { public long inQuotaTimeElapsed; /** - * The time after which the app will be under the bucket quota and can start running - * low priority jobs again. This is only valid if - * {@link #executionTimeInWindowMs} >= - * {@link #mAllowedTimePerPeriodMs} * (1 - {@link #mAllowedTimeSurplusPriorityLow}), - * {@link #executionTimeInMaxPeriodMs} >= {@link #mMaxExecutionTimeMs}, - * {@link #bgJobCountInWindow} >= {@link #jobCountLimit}, or - * {@link #sessionCountInWindow} >= {@link #sessionCountLimit}. - */ - public long inQuotaTimeLowElapsed; - - /** - * The time after which the app will be under the bucket quota and can start running - * min priority jobs again. This is only valid if - * {@link #executionTimeInWindowMs} >= - * {@link #mAllowedTimePerPeriodMs} * (1 - {@link #mAllowedTimeSurplusPriorityMin}), - * {@link #executionTimeInMaxPeriodMs} >= {@link #mMaxExecutionTimeMs}, - * {@link #bgJobCountInWindow} >= {@link #jobCountLimit}, or - * {@link #sessionCountInWindow} >= {@link #sessionCountLimit}. - */ - public long inQuotaTimeMinElapsed; - - /** * The time after which {@link #jobCountInRateLimitingWindow} should be considered invalid, * in the elapsed realtime timebase. */ @@ -227,8 +204,6 @@ public final class QuotaController extends StateController { + "bgJobCountInMaxPeriod=" + bgJobCountInMaxPeriod + ", " + "sessionCountInWindow=" + sessionCountInWindow + ", " + "inQuotaTime=" + inQuotaTimeElapsed + ", " - + "inQuotaTimeLow=" + inQuotaTimeLowElapsed + ", " - + "inQuotaTimeMin=" + inQuotaTimeMinElapsed + ", " + "rateLimitJobCountExpirationTime=" + jobRateLimitExpirationTimeElapsed + ", " + "rateLimitJobCountWindow=" + jobCountInRateLimitingWindow + ", " + "rateLimitSessionCountExpirationTime=" @@ -385,24 +360,6 @@ public final class QuotaController extends StateController { */ private long mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs; - /** - * The percentage of {@link #mAllowedTimePerPeriodMs} that should not be used by - * {@link JobInfo#PRIORITY_LOW low priority} jobs. In other words, there must be a minimum - * surplus of this amount of remaining allowed time before we start running low priority - * jobs. - */ - private float mAllowedTimeSurplusPriorityLow = - QcConstants.DEFAULT_ALLOWED_TIME_SURPLUS_PRIORITY_LOW; - - /** - * The percentage of {@link #mAllowedTimePerPeriodMs} that should not be used by - * {@link JobInfo#PRIORITY_MIN min priority} jobs. In other words, there must be a minimum - * surplus of this amount of remaining allowed time before we start running low priority - * jobs. - */ - private float mAllowedTimeSurplusPriorityMin = - QcConstants.DEFAULT_ALLOWED_TIME_SURPLUS_PRIORITY_MIN; - /** The period of time used to rate limit recently run jobs. */ private long mRateLimitingWindowMs = QcConstants.DEFAULT_RATE_LIMITING_WINDOW_MS; @@ -828,8 +785,7 @@ public final class QuotaController extends StateController { return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS; } return getTimeUntilQuotaConsumedLocked( - jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), - jobStatus.getEffectivePriority()); + jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()); } // Expedited job. @@ -919,8 +875,7 @@ public final class QuotaController extends StateController { return isTopStartedJobLocked(jobStatus) || isUidInForeground(jobStatus.getSourceUid()) || isWithinQuotaLocked( - jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket, - jobStatus.getEffectivePriority()); + jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket); } @GuardedBy("mLock") @@ -937,7 +892,7 @@ public final class QuotaController extends StateController { @VisibleForTesting @GuardedBy("mLock") boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName, - final int standbyBucket, final int priority) { + final int standbyBucket) { if (!mIsEnabled) { return true; } @@ -945,18 +900,9 @@ public final class QuotaController extends StateController { if (isQuotaFreeLocked(standbyBucket)) return true; - final long minSurplus; - if (priority <= JobInfo.PRIORITY_MIN) { - minSurplus = (long) - (mAllowedTimePerPeriodMs[standbyBucket] * mAllowedTimeSurplusPriorityMin); - } else if (priority <= JobInfo.PRIORITY_LOW) { - minSurplus = (long) - (mAllowedTimePerPeriodMs[standbyBucket] * mAllowedTimeSurplusPriorityLow); - } else { - minSurplus = 0; - } ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket); - return getRemainingExecutionTimeLocked(stats) > minSurplus + // TODO: use a higher minimum remaining time for jobs with MINIMUM priority + return getRemainingExecutionTimeLocked(stats) > 0 && isUnderJobCountQuotaLocked(stats, standbyBucket) && isUnderSessionCountQuotaLocked(stats, standbyBucket); } @@ -1074,8 +1020,7 @@ public final class QuotaController extends StateController { * job is running. */ @VisibleForTesting - long getTimeUntilQuotaConsumedLocked(final int userId, @NonNull final String packageName, - @JobInfo.Priority int jobPriority) { + long getTimeUntilQuotaConsumedLocked(final int userId, @NonNull final String packageName) { final long nowElapsed = sElapsedRealtimeClock.millis(); final int standbyBucket = JobSchedulerService.standbyBucketForPackage( packageName, userId, nowElapsed); @@ -1096,15 +1041,11 @@ public final class QuotaController extends StateController { final long startWindowElapsed = nowElapsed - stats.windowSizeMs; final long startMaxElapsed = nowElapsed - MAX_PERIOD_MS; - final long allowedTimePerPeriodMs = getAllowedTimePerPeriodMs(standbyBucket, jobPriority); + final long allowedTimePerPeriodMs = mAllowedTimePerPeriodMs[standbyBucket]; final long allowedTimeRemainingMs = allowedTimePerPeriodMs - stats.executionTimeInWindowMs; final long maxExecutionTimeRemainingMs = mMaxExecutionTimeMs - stats.executionTimeInMaxPeriodMs; - if (maxExecutionTimeRemainingMs < 0) { - return 0; - } - // Regular ACTIVE case. Since the bucket size equals the allowed time, the app jobs can // essentially run until they reach the maximum limit. if (stats.windowSizeMs == mAllowedTimePerPeriodMs[standbyBucket]) { @@ -1112,10 +1053,6 @@ public final class QuotaController extends StateController { sessions, startMaxElapsed, maxExecutionTimeRemainingMs); } - if (allowedTimeRemainingMs < 0) { - return 0; - } - // Need to check both max time and period time in case one is less than the other. // For example, max time remaining could be less than bucket time remaining, but sessions // contributing to the max time remaining could phase out enough that we'd want to use the @@ -1127,21 +1064,6 @@ public final class QuotaController extends StateController { sessions, startWindowElapsed, allowedTimeRemainingMs)); } - private long getAllowedTimePerPeriodMs(int standbyBucket, @JobInfo.Priority int jobPriority) { - return getAllowedTimePerPeriodMs(mAllowedTimePerPeriodMs[standbyBucket], jobPriority); - } - - private long getAllowedTimePerPeriodMs(long initialAllowedTime, - @JobInfo.Priority int jobPriority) { - if (jobPriority <= JobInfo.PRIORITY_MIN) { - return (long) (initialAllowedTime * (1 - mAllowedTimeSurplusPriorityMin)); - } - if (jobPriority <= JobInfo.PRIORITY_LOW) { - return (long) (initialAllowedTime * (1 - mAllowedTimeSurplusPriorityLow)); - } - return initialAllowedTime; - } - /** * Calculates how much time it will take, in milliseconds, until the quota is fully consumed. * @@ -1299,15 +1221,10 @@ public final class QuotaController extends StateController { stats.sessionCountInWindow = 0; if (stats.jobCountLimit == 0 || stats.sessionCountLimit == 0) { // App won't be in quota until configuration changes. - stats.inQuotaTimeElapsed = stats.inQuotaTimeLowElapsed = stats.inQuotaTimeMinElapsed = - Long.MAX_VALUE; + stats.inQuotaTimeElapsed = Long.MAX_VALUE; } else { stats.inQuotaTimeElapsed = 0; } - final long allowedTimeMinMs = - getAllowedTimePerPeriodMs(stats.allowedTimePerPeriodMs, JobInfo.PRIORITY_MIN); - final long allowedTimeLowMs = - getAllowedTimePerPeriodMs(stats.allowedTimePerPeriodMs, JobInfo.PRIORITY_LOW); final long allowedTimeIntoQuotaMs = stats.allowedTimePerPeriodMs - mQuotaBufferMs; Timer timer = mPkgTimers.get(userId, packageName); @@ -1326,25 +1243,13 @@ public final class QuotaController extends StateController { stats.inQuotaTimeElapsed = Math.max(stats.inQuotaTimeElapsed, nowElapsed - allowedTimeIntoQuotaMs + stats.windowSizeMs); } - if (stats.executionTimeInWindowMs >= allowedTimeLowMs) { - stats.inQuotaTimeLowElapsed = Math.max(stats.inQuotaTimeLowElapsed, - nowElapsed - allowedTimeLowMs + stats.windowSizeMs); - } - if (stats.executionTimeInWindowMs >= allowedTimeMinMs) { - stats.inQuotaTimeMinElapsed = Math.max(stats.inQuotaTimeMinElapsed, - nowElapsed - allowedTimeMinMs + stats.windowSizeMs); - } if (stats.executionTimeInMaxPeriodMs >= mMaxExecutionTimeIntoQuotaMs) { final long inQuotaTime = nowElapsed - mMaxExecutionTimeIntoQuotaMs + MAX_PERIOD_MS; stats.inQuotaTimeElapsed = Math.max(stats.inQuotaTimeElapsed, inQuotaTime); - stats.inQuotaTimeLowElapsed = Math.max(stats.inQuotaTimeLowElapsed, inQuotaTime); - stats.inQuotaTimeMinElapsed = Math.max(stats.inQuotaTimeMinElapsed, inQuotaTime); } if (stats.bgJobCountInWindow >= stats.jobCountLimit) { final long inQuotaTime = nowElapsed + stats.windowSizeMs; stats.inQuotaTimeElapsed = Math.max(stats.inQuotaTimeElapsed, inQuotaTime); - stats.inQuotaTimeLowElapsed = Math.max(stats.inQuotaTimeLowElapsed, inQuotaTime); - stats.inQuotaTimeMinElapsed = Math.max(stats.inQuotaTimeMinElapsed, inQuotaTime); } } @@ -1386,23 +1291,9 @@ public final class QuotaController extends StateController { start + stats.executionTimeInWindowMs - allowedTimeIntoQuotaMs + stats.windowSizeMs); } - if (stats.executionTimeInWindowMs >= allowedTimeLowMs) { - stats.inQuotaTimeLowElapsed = Math.max(stats.inQuotaTimeLowElapsed, - start + stats.executionTimeInWindowMs - allowedTimeLowMs - + stats.windowSizeMs); - } - if (stats.executionTimeInWindowMs >= allowedTimeMinMs) { - stats.inQuotaTimeMinElapsed = Math.max(stats.inQuotaTimeMinElapsed, - start + stats.executionTimeInWindowMs - allowedTimeMinMs - + stats.windowSizeMs); - } if (stats.bgJobCountInWindow >= stats.jobCountLimit) { final long inQuotaTime = session.endTimeElapsed + stats.windowSizeMs; stats.inQuotaTimeElapsed = Math.max(stats.inQuotaTimeElapsed, inQuotaTime); - stats.inQuotaTimeLowElapsed = Math.max(stats.inQuotaTimeLowElapsed, - inQuotaTime); - stats.inQuotaTimeMinElapsed = Math.max(stats.inQuotaTimeMinElapsed, - inQuotaTime); } if (i == loopStart || (sessions.get(i + 1).startTimeElapsed - session.endTimeElapsed) @@ -1413,10 +1304,6 @@ public final class QuotaController extends StateController { if (sessionCountInWindow >= stats.sessionCountLimit) { final long inQuotaTime = session.endTimeElapsed + stats.windowSizeMs; stats.inQuotaTimeElapsed = Math.max(stats.inQuotaTimeElapsed, inQuotaTime); - stats.inQuotaTimeLowElapsed = Math.max(stats.inQuotaTimeLowElapsed, - inQuotaTime); - stats.inQuotaTimeMinElapsed = Math.max(stats.inQuotaTimeMinElapsed, - inQuotaTime); } } } @@ -1706,7 +1593,7 @@ public final class QuotaController extends StateController { /** * Update the CONSTRAINT_WITHIN_QUOTA bit for all of the Jobs for a given package. * - * @return true if at least one job had its bit changed + * @return the set of jobs whose status changed */ @NonNull private ArraySet<JobStatus> maybeUpdateConstraintForPkgLocked(final long nowElapsed, @@ -1719,8 +1606,7 @@ public final class QuotaController extends StateController { // Quota is the same for all jobs within a package. final int realStandbyBucket = jobs.valueAt(0).getStandbyBucket(); - final boolean realInQuota = isWithinQuotaLocked( - userId, packageName, realStandbyBucket, JobInfo.PRIORITY_DEFAULT); + final boolean realInQuota = isWithinQuotaLocked(userId, packageName, realStandbyBucket); boolean outOfEJQuota = false; for (int i = jobs.size() - 1; i >= 0; --i) { final JobStatus js = jobs.valueAt(i); @@ -1733,8 +1619,7 @@ public final class QuotaController extends StateController { changedJobs.add(js); } } else if (realStandbyBucket != EXEMPTED_INDEX && realStandbyBucket != ACTIVE_INDEX - && realStandbyBucket == js.getEffectiveStandbyBucket() - && js.getEffectivePriority() >= JobInfo.PRIORITY_DEFAULT) { + && realStandbyBucket == js.getEffectiveStandbyBucket()) { // An app in the ACTIVE bucket may be out of quota while the job could be in quota // for some reason. Therefore, avoid setting the real value here and check each job // individually. @@ -1798,8 +1683,9 @@ public final class QuotaController extends StateController { final String packageName = jobStatus.getSourcePackageName(); final int realStandbyBucket = jobStatus.getStandbyBucket(); if (isWithinEJQuota - && isWithinQuotaLocked(userId, packageName, realStandbyBucket, - JobInfo.PRIORITY_MIN)) { + && isWithinQuotaLocked(userId, packageName, realStandbyBucket)) { + // TODO(141645789): we probably shouldn't cancel the alarm until we've verified + // that all jobs for the userId-package are within quota. mInQuotaAlarmQueue.removeAlarmForKey(new Package(userId, packageName)); } else { mToScheduleStartAlarms.add(userId, packageName, realStandbyBucket); @@ -1860,25 +1746,8 @@ public final class QuotaController extends StateController { standbyBucket); final long remainingEJQuota = getRemainingEJExecutionTimeLocked(userId, packageName); - int minPriority = JobInfo.PRIORITY_MAX; - boolean hasDefPlus = false, hasLow = false, hasMin = false; - for (int i = jobs.size() - 1; i >= 0; --i) { - final int priority = jobs.valueAt(i).getEffectivePriority(); - minPriority = Math.min(minPriority, priority); - if (priority <= JobInfo.PRIORITY_MIN) { - hasMin = true; - } else if (priority <= JobInfo.PRIORITY_LOW) { - hasLow = true; - } else { - hasDefPlus = true; - } - if (hasMin && hasLow && hasDefPlus) { - break; - } - } final boolean inRegularQuota = - stats.executionTimeInWindowMs - < getAllowedTimePerPeriodMs(standbyBucket, minPriority) + stats.executionTimeInWindowMs < mAllowedTimePerPeriodMs[standbyBucket] && stats.executionTimeInMaxPeriodMs < mMaxExecutionTimeMs && isUnderJobCountQuota && isUnderTimingSessionCountQuota; @@ -1900,24 +1769,7 @@ public final class QuotaController extends StateController { long inEJQuotaTimeElapsed = Long.MAX_VALUE; if (!inRegularQuota) { // The time this app will have quota again. - long executionInQuotaTime = Long.MAX_VALUE; - boolean hasExecutionInQuotaTime = false; - if (hasMin && stats.inQuotaTimeMinElapsed > 0) { - executionInQuotaTime = Math.min(executionInQuotaTime, stats.inQuotaTimeMinElapsed); - hasExecutionInQuotaTime = true; - } - if (hasLow && stats.inQuotaTimeLowElapsed > 0) { - executionInQuotaTime = Math.min(executionInQuotaTime, stats.inQuotaTimeLowElapsed); - hasExecutionInQuotaTime = true; - } - if (hasDefPlus && stats.inQuotaTimeElapsed > 0) { - executionInQuotaTime = Math.min(executionInQuotaTime, stats.inQuotaTimeElapsed); - hasExecutionInQuotaTime = true; - } - long inQuotaTimeElapsed = 0; - if (hasExecutionInQuotaTime) { - inQuotaTimeElapsed = executionInQuotaTime; - } + long inQuotaTimeElapsed = stats.inQuotaTimeElapsed; if (!isUnderJobCountQuota && stats.bgJobCountInWindow < stats.jobCountLimit) { // App hit the rate limit. inQuotaTimeElapsed = @@ -2130,7 +1982,6 @@ public final class QuotaController extends StateController { private final ArraySet<JobStatus> mRunningBgJobs = new ArraySet<>(); private long mStartTimeElapsed; private int mBgJobCount; - private int mLowestPriority = JobInfo.PRIORITY_MAX; private long mDebitAdjustment; Timer(int uid, int userId, String packageName, boolean regularJobTimer) { @@ -2153,8 +2004,6 @@ public final class QuotaController extends StateController { Slog.v(TAG, "Starting to track " + jobStatus.toShortString()); } // Always maintain list of running jobs, even when quota is free. - final boolean priorityLowered = mLowestPriority > jobStatus.getEffectivePriority(); - mLowestPriority = Math.min(mLowestPriority, jobStatus.getEffectivePriority()); if (mRunningBgJobs.add(jobStatus) && shouldTrackLocked()) { mBgJobCount++; if (mRegularJobTimer) { @@ -2170,8 +2019,6 @@ public final class QuotaController extends StateController { invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName); } scheduleCutoff(); - } else if (mRegularJobTimer && priorityLowered) { - rescheduleCutoff(); } } } @@ -2196,19 +2043,6 @@ public final class QuotaController extends StateController { && !isQuotaFreeLocked(standbyBucket)) { emitSessionLocked(nowElapsed); cancelCutoff(); - mLowestPriority = JobInfo.PRIORITY_MAX; - } else if (mRegularJobTimer - && mLowestPriority == jobStatus.getEffectivePriority()) { - // Lowest priority doesn't matter for EJ timers. - final int oldPriority = mLowestPriority; - mLowestPriority = JobInfo.PRIORITY_MAX; - for (int i = mRunningBgJobs.size() - 1; i >= 0; --i) { - mLowestPriority = Math.min(mLowestPriority, - mRunningBgJobs.valueAt(i).getEffectivePriority()); - } - if (mLowestPriority != oldPriority) { - rescheduleCutoff(); - } } } } @@ -2335,14 +2169,9 @@ public final class QuotaController extends StateController { } Message msg = mHandler.obtainMessage( mRegularJobTimer ? MSG_REACHED_QUOTA : MSG_REACHED_EJ_QUOTA, mPkg); - final long timeRemainingMs; - if (mRegularJobTimer) { - timeRemainingMs = getTimeUntilQuotaConsumedLocked( - mPkg.userId, mPkg.packageName, mLowestPriority); - } else { - timeRemainingMs = - getTimeUntilEJQuotaConsumedLocked(mPkg.userId, mPkg.packageName); - } + final long timeRemainingMs = mRegularJobTimer + ? getTimeUntilQuotaConsumedLocked(mPkg.userId, mPkg.packageName) + : getTimeUntilEJQuotaConsumedLocked(mPkg.userId, mPkg.packageName); if (DEBUG) { Slog.i(TAG, (mRegularJobTimer ? "Regular job" : "EJ") + " for " + mPkg + " has " @@ -2695,19 +2524,26 @@ public final class QuotaController extends StateController { Slog.d(TAG, "Checking if " + pkg + " has reached its quota."); } - final ArraySet<JobStatus> changedJobs = maybeUpdateConstraintForPkgLocked( - sElapsedRealtimeClock.millis(), pkg.userId, pkg.packageName); - if (changedJobs.size() > 0) { + long timeRemainingMs = getRemainingExecutionTimeLocked(pkg.userId, + pkg.packageName); + if (timeRemainingMs <= 50) { + // Less than 50 milliseconds left. Start process of shutting down jobs. if (DEBUG) Slog.d(TAG, pkg + " has reached its quota."); - mStateChangedListener.onControllerStateChanged(changedJobs); + mStateChangedListener.onControllerStateChanged( + maybeUpdateConstraintForPkgLocked( + sElapsedRealtimeClock.millis(), + pkg.userId, pkg.packageName)); } else { // This could potentially happen if an old session phases out while a // job is currently running. // Reschedule message + Message rescheduleMsg = obtainMessage(MSG_REACHED_QUOTA, pkg); + timeRemainingMs = getTimeUntilQuotaConsumedLocked(pkg.userId, + pkg.packageName); if (DEBUG) { - Slog.d(TAG, pkg + " had early REACHED_QUOTA message"); + Slog.d(TAG, pkg + " has " + timeRemainingMs + "ms left."); } - mPkgTimers.get(pkg.userId, pkg.packageName).rescheduleCutoff(); + sendMessageDelayed(rescheduleMsg, timeRemainingMs); } break; } @@ -2717,19 +2553,25 @@ public final class QuotaController extends StateController { Slog.d(TAG, "Checking if " + pkg + " has reached its EJ quota."); } - final ArraySet<JobStatus> changedJobs = maybeUpdateConstraintForPkgLocked( - sElapsedRealtimeClock.millis(), pkg.userId, pkg.packageName); - if (changedJobs.size() > 0) { + long timeRemainingMs = getRemainingEJExecutionTimeLocked( + pkg.userId, pkg.packageName); + if (timeRemainingMs <= 0) { if (DEBUG) Slog.d(TAG, pkg + " has reached its EJ quota."); - mStateChangedListener.onControllerStateChanged(changedJobs); + mStateChangedListener.onControllerStateChanged( + maybeUpdateConstraintForPkgLocked( + sElapsedRealtimeClock.millis(), + pkg.userId, pkg.packageName)); } else { // This could potentially happen if an old session phases out while a // job is currently running. // Reschedule message + Message rescheduleMsg = obtainMessage(MSG_REACHED_EJ_QUOTA, pkg); + timeRemainingMs = getTimeUntilEJQuotaConsumedLocked( + pkg.userId, pkg.packageName); if (DEBUG) { - Slog.d(TAG, pkg + " had early REACHED_EJ_QUOTA message"); + Slog.d(TAG, pkg + " has " + timeRemainingMs + "ms left for EJ"); } - mEJPkgTimers.get(pkg.userId, pkg.packageName).rescheduleCutoff(); + sendMessageDelayed(rescheduleMsg, timeRemainingMs); } break; } @@ -2993,12 +2835,6 @@ public final class QuotaController extends StateController { static final String KEY_IN_QUOTA_BUFFER_MS = QC_CONSTANT_PREFIX + "in_quota_buffer_ms"; @VisibleForTesting - static final String KEY_ALLOWED_TIME_SURPLUS_PRIORITY_LOW = - QC_CONSTANT_PREFIX + "allowed_time_surplus_priority_low"; - @VisibleForTesting - static final String KEY_ALLOWED_TIME_SURPLUS_PRIORITY_MIN = - QC_CONSTANT_PREFIX + "allowed_time_surplus_priority_min"; - @VisibleForTesting static final String KEY_WINDOW_SIZE_EXEMPTED_MS = QC_CONSTANT_PREFIX + "window_size_exempted_ms"; @VisibleForTesting @@ -3130,8 +2966,6 @@ public final class QuotaController extends StateController { 10 * 60 * 1000L; // 10 minutes private static final long DEFAULT_IN_QUOTA_BUFFER_MS = 30 * 1000L; // 30 seconds - private static final float DEFAULT_ALLOWED_TIME_SURPLUS_PRIORITY_LOW = .25f; - private static final float DEFAULT_ALLOWED_TIME_SURPLUS_PRIORITY_MIN = .5f; private static final long DEFAULT_WINDOW_SIZE_EXEMPTED_MS = DEFAULT_ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS; // EXEMPT apps can run jobs at any time private static final long DEFAULT_WINDOW_SIZE_ACTIVE_MS = @@ -3230,22 +3064,6 @@ public final class QuotaController extends StateController { public long IN_QUOTA_BUFFER_MS = DEFAULT_IN_QUOTA_BUFFER_MS; /** - * The percentage of ALLOWED_TIME_PER_PERIOD_*_MS that should not be used by - * {@link JobInfo#PRIORITY_LOW low priority} jobs. In other words, there must be a minimum - * surplus of this amount of remaining allowed time before we start running low priority - * jobs. - */ - public float ALLOWED_TIME_SURPLUS_PRIORITY_LOW = DEFAULT_ALLOWED_TIME_SURPLUS_PRIORITY_LOW; - - /** - * The percentage of ALLOWED_TIME_PER_PERIOD_*_MS that should not be used by - * {@link JobInfo#PRIORITY_MIN low priority} jobs. In other words, there must be a minimum - * surplus of this amount of remaining allowed time before we start running min priority - * jobs. - */ - public float ALLOWED_TIME_SURPLUS_PRIORITY_MIN = DEFAULT_ALLOWED_TIME_SURPLUS_PRIORITY_MIN; - - /** * The quota window size of the particular standby bucket. Apps in this standby bucket are * expected to run only {@link #ALLOWED_TIME_PER_PERIOD_EXEMPTED_MS} within the past * WINDOW_SIZE_MS. @@ -3514,8 +3332,6 @@ public final class QuotaController extends StateController { case KEY_ALLOWED_TIME_PER_PERIOD_FREQUENT_MS: case KEY_ALLOWED_TIME_PER_PERIOD_RARE_MS: case KEY_ALLOWED_TIME_PER_PERIOD_RESTRICTED_MS: - case KEY_ALLOWED_TIME_SURPLUS_PRIORITY_LOW: - case KEY_ALLOWED_TIME_SURPLUS_PRIORITY_MIN: case KEY_IN_QUOTA_BUFFER_MS: case KEY_MAX_EXECUTION_TIME_MS: case KEY_WINDOW_SIZE_ACTIVE_MS: @@ -3757,7 +3573,6 @@ public final class QuotaController extends StateController { KEY_ALLOWED_TIME_PER_PERIOD_WORKING_MS, KEY_ALLOWED_TIME_PER_PERIOD_FREQUENT_MS, KEY_ALLOWED_TIME_PER_PERIOD_RARE_MS, KEY_ALLOWED_TIME_PER_PERIOD_RESTRICTED_MS, KEY_IN_QUOTA_BUFFER_MS, - KEY_ALLOWED_TIME_SURPLUS_PRIORITY_LOW, KEY_ALLOWED_TIME_SURPLUS_PRIORITY_MIN, KEY_MAX_EXECUTION_TIME_MS, KEY_WINDOW_SIZE_EXEMPTED_MS, KEY_WINDOW_SIZE_ACTIVE_MS, KEY_WINDOW_SIZE_WORKING_MS, @@ -3781,12 +3596,6 @@ public final class QuotaController extends StateController { ALLOWED_TIME_PER_PERIOD_RESTRICTED_MS = properties.getLong(KEY_ALLOWED_TIME_PER_PERIOD_RESTRICTED_MS, DEFAULT_ALLOWED_TIME_PER_PERIOD_RESTRICTED_MS); - ALLOWED_TIME_SURPLUS_PRIORITY_LOW = - properties.getFloat(KEY_ALLOWED_TIME_SURPLUS_PRIORITY_LOW, - DEFAULT_ALLOWED_TIME_SURPLUS_PRIORITY_LOW); - ALLOWED_TIME_SURPLUS_PRIORITY_MIN = - properties.getFloat(KEY_ALLOWED_TIME_SURPLUS_PRIORITY_MIN, - DEFAULT_ALLOWED_TIME_SURPLUS_PRIORITY_MIN); IN_QUOTA_BUFFER_MS = properties.getLong(KEY_IN_QUOTA_BUFFER_MS, DEFAULT_IN_QUOTA_BUFFER_MS); MAX_EXECUTION_TIME_MS = properties.getLong(KEY_MAX_EXECUTION_TIME_MS, @@ -3865,23 +3674,6 @@ public final class QuotaController extends StateController { mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs; mShouldReevaluateConstraints = true; } - // Low priority surplus should be in the range [0, .9]. A value of 1 would essentially - // mean never run low priority jobs. - float newAllowedTimeSurplusPriorityLow = - Math.max(0f, Math.min(.9f, ALLOWED_TIME_SURPLUS_PRIORITY_LOW)); - if (Float.compare( - mAllowedTimeSurplusPriorityLow, newAllowedTimeSurplusPriorityLow) != 0) { - mAllowedTimeSurplusPriorityLow = newAllowedTimeSurplusPriorityLow; - mShouldReevaluateConstraints = true; - } - // Min priority surplus should be in the range [0, mAllowedTimeSurplusPriorityLow]. - float newAllowedTimeSurplusPriorityMin = Math.max(0f, - Math.min(mAllowedTimeSurplusPriorityLow, ALLOWED_TIME_SURPLUS_PRIORITY_MIN)); - if (Float.compare( - mAllowedTimeSurplusPriorityMin, newAllowedTimeSurplusPriorityMin) != 0) { - mAllowedTimeSurplusPriorityMin = newAllowedTimeSurplusPriorityMin; - mShouldReevaluateConstraints = true; - } long newExemptedPeriodMs = Math.max(mAllowedTimePerPeriodMs[EXEMPTED_INDEX], Math.min(MAX_PERIOD_MS, WINDOW_SIZE_EXEMPTED_MS)); if (mBucketPeriodsMs[EXEMPTED_INDEX] != newExemptedPeriodMs) { @@ -4081,10 +3873,6 @@ public final class QuotaController extends StateController { .println(); pw.print(KEY_ALLOWED_TIME_PER_PERIOD_RESTRICTED_MS, ALLOWED_TIME_PER_PERIOD_RESTRICTED_MS).println(); - pw.print(KEY_ALLOWED_TIME_SURPLUS_PRIORITY_LOW, ALLOWED_TIME_SURPLUS_PRIORITY_LOW) - .println(); - pw.print(KEY_ALLOWED_TIME_SURPLUS_PRIORITY_MIN, ALLOWED_TIME_SURPLUS_PRIORITY_MIN) - .println(); pw.print(KEY_IN_QUOTA_BUFFER_MS, IN_QUOTA_BUFFER_MS).println(); pw.print(KEY_WINDOW_SIZE_EXEMPTED_MS, WINDOW_SIZE_EXEMPTED_MS).println(); pw.print(KEY_WINDOW_SIZE_ACTIVE_MS, WINDOW_SIZE_ACTIVE_MS).println(); @@ -4210,16 +3998,6 @@ public final class QuotaController extends StateController { } @VisibleForTesting - float getAllowedTimeSurplusPriorityLow() { - return mAllowedTimeSurplusPriorityLow; - } - - @VisibleForTesting - float getAllowedTimeSurplusPriorityMin() { - return mAllowedTimeSurplusPriorityMin; - } - - @VisibleForTesting @NonNull int[] getBucketMaxJobCounts() { return mMaxBucketJobCounts; 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 cae6cdcf8f1f..54c3db48231d 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -104,6 +104,7 @@ import android.util.IndentingPrintWriter; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; +import android.util.SparseLongArray; import android.util.TimeUtils; import android.view.Display; import android.widget.Toast; @@ -260,6 +261,13 @@ public class AppStandbyController private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1); + /** + * Set of user IDs and the next time (in the elapsed realtime timebase) when we should check the + * apps' idle states. + */ + @GuardedBy("mPendingIdleStateChecks") + private final SparseLongArray mPendingIdleStateChecks = new SparseLongArray(); + // Cache the active network scorer queried from the network scorer service private volatile String mCachedNetworkScorer = null; // The last time the network scorer service was queried @@ -722,7 +730,14 @@ public class AppStandbyController @Override public void postCheckIdleStates(int userId) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0)); + if (userId == UserHandle.USER_ALL) { + postOneTimeCheckIdleStates(); + } else { + synchronized (mPendingIdleStateChecks) { + mPendingIdleStateChecks.put(userId, mInjector.elapsedRealtime()); + } + mHandler.obtainMessage(MSG_CHECK_IDLE_STATES).sendToTarget(); + } } @Override @@ -2374,10 +2389,32 @@ public class AppStandbyController break; case MSG_CHECK_IDLE_STATES: - if (checkIdleStates(msg.arg1) && mAppIdleEnabled) { - mHandler.sendMessageDelayed(mHandler.obtainMessage( - MSG_CHECK_IDLE_STATES, msg.arg1, 0), - mCheckIdleIntervalMillis); + removeMessages(MSG_CHECK_IDLE_STATES); + + long earliestCheck = Long.MAX_VALUE; + final long nowElapsed = mInjector.elapsedRealtime(); + synchronized (mPendingIdleStateChecks) { + for (int i = mPendingIdleStateChecks.size() - 1; i >= 0; --i) { + long expirationTime = mPendingIdleStateChecks.valueAt(i); + + if (expirationTime <= nowElapsed) { + final int userId = mPendingIdleStateChecks.keyAt(i); + if (checkIdleStates(userId) && mAppIdleEnabled) { + expirationTime = nowElapsed + mCheckIdleIntervalMillis; + mPendingIdleStateChecks.put(userId, expirationTime); + } else { + mPendingIdleStateChecks.removeAt(i); + continue; + } + } + + earliestCheck = Math.min(earliestCheck, expirationTime); + } + } + if (earliestCheck != Long.MAX_VALUE) { + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_CHECK_IDLE_STATES), + earliestCheck - nowElapsed); } break; diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp index 150ab9991a2d..ec0b79b34c02 100644 --- a/cmds/incidentd/src/incidentd_util.cpp +++ b/cmds/incidentd/src/incidentd_util.cpp @@ -184,11 +184,26 @@ static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) { sigemptyset(&child_mask); sigaddset(&child_mask, SIGCHLD); + // block SIGCHLD before we check if a process has exited if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) { - ALOGW("sigprocmask failed: %s", strerror(errno)); + ALOGW("*** sigprocmask failed: %s\n", strerror(errno)); return false; } + // if the child has exited already, handle and reset signals before leaving + pid_t child_pid = waitpid(pid, status, WNOHANG); + if (child_pid != pid) { + if (child_pid > 0) { + ALOGW("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid); + sigprocmask(SIG_SETMASK, &old_mask, nullptr); + return false; + } + } else { + sigprocmask(SIG_SETMASK, &old_mask, nullptr); + return true; + } + + // wait for a SIGCHLD timespec ts; ts.tv_sec = timeout_ms / 1000; ts.tv_nsec = (timeout_ms % 1000) * 1000000; @@ -197,7 +212,7 @@ static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) { // Set the signals back the way they were. if (sigprocmask(SIG_SETMASK, &old_mask, nullptr) == -1) { - ALOGW("sigprocmask failed: %s", strerror(errno)); + ALOGW("*** sigprocmask failed: %s\n", strerror(errno)); if (ret == 0) { return false; } @@ -207,21 +222,21 @@ static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) { if (errno == EAGAIN) { errno = ETIMEDOUT; } else { - ALOGW("sigtimedwait failed: %s", strerror(errno)); + ALOGW("*** sigtimedwait failed: %s\n", strerror(errno)); } return false; } - pid_t child_pid = waitpid(pid, status, WNOHANG); - if (child_pid == pid) { - return true; - } - if (child_pid == -1) { - ALOGW("waitpid failed: %s", strerror(errno)); - } else { - ALOGW("Waiting for pid %d, got pid %d instead", pid, child_pid); + child_pid = waitpid(pid, status, WNOHANG); + if (child_pid != pid) { + if (child_pid != -1) { + ALOGW("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid); + } else { + ALOGW("*** waitpid failed: %s\n", strerror(errno)); + } + return false; } - return false; + return true; } status_t kill_child(pid_t pid) { diff --git a/core/api/current.txt b/core/api/current.txt index 00d7d80808b1..e695cf61022f 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -10329,7 +10329,6 @@ package android.content { field public static final String ACTION_VIEW_LOCUS = "android.intent.action.VIEW_LOCUS"; field @RequiresPermission(android.Manifest.permission.START_VIEW_PERMISSION_USAGE) public static final String ACTION_VIEW_PERMISSION_USAGE = "android.intent.action.VIEW_PERMISSION_USAGE"; field @RequiresPermission(android.Manifest.permission.START_VIEW_PERMISSION_USAGE) public static final String ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD = "android.intent.action.VIEW_PERMISSION_USAGE_FOR_PERIOD"; - field @RequiresPermission("android.permission.MANAGE_SENSOR_PRIVACY") public static final String ACTION_VIEW_SAFETY_HUB = "android.intent.action.VIEW_SAFETY_HUB"; field public static final String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND"; field @Deprecated public static final String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED"; field public static final String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH"; @@ -26831,7 +26830,7 @@ package android.net { field public static final String EXTRA_ERROR_CLASS = "android.net.extra.ERROR_CLASS"; field public static final String EXTRA_ERROR_CODE = "android.net.extra.ERROR_CODE"; field public static final String EXTRA_SESSION_KEY = "android.net.extra.SESSION_KEY"; - field public static final String EXTRA_TIMESTAMP = "android.net.extra.TIMESTAMP"; + field public static final String EXTRA_TIMESTAMP_MILLIS = "android.net.extra.TIMESTAMP_MILLIS"; field public static final String EXTRA_UNDERLYING_LINK_PROPERTIES = "android.net.extra.UNDERLYING_LINK_PROPERTIES"; field public static final String EXTRA_UNDERLYING_NETWORK = "android.net.extra.UNDERLYING_NETWORK"; field public static final String EXTRA_UNDERLYING_NETWORK_CAPABILITIES = "android.net.extra.UNDERLYING_NETWORK_CAPABILITIES"; @@ -31576,7 +31575,7 @@ package android.os { method @Deprecated @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader); method @Nullable public <T> android.os.Parcelable.Creator<T> readParcelableCreator(@Nullable ClassLoader, @NonNull Class<T>); method @Deprecated @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader); - method @NonNull public <T> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader, @NonNull Class<T>); + method @NonNull public <T> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader, @NonNull Class<? extends T>); method @Nullable public android.os.PersistableBundle readPersistableBundle(); method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader); method @Deprecated @Nullable public java.io.Serializable readSerializable(); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 83464f0ca1df..e611d6b16bd7 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2823,11 +2823,14 @@ package android.companion.virtual { public final class VirtualDeviceParams implements android.os.Parcelable { method public int describeContents(); - method @Nullable public java.util.Set<android.content.ComponentName> getAllowedActivities(); - method @Nullable public java.util.Set<android.content.ComponentName> getBlockedActivities(); + method @NonNull public java.util.Set<android.content.ComponentName> getAllowedActivities(); + method @NonNull public java.util.Set<android.content.ComponentName> getBlockedActivities(); + method public int getDefaultActivityPolicy(); method public int getLockState(); method @NonNull public java.util.Set<android.os.UserHandle> getUsersWithMatchingAccounts(); method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int ACTIVITY_POLICY_DEFAULT_ALLOWED = 0; // 0x0 + field public static final int ACTIVITY_POLICY_DEFAULT_BLOCKED = 1; // 0x1 field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDeviceParams> CREATOR; field public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1; // 0x1 field public static final int LOCK_STATE_DEFAULT = 0; // 0x0 @@ -2836,8 +2839,8 @@ package android.companion.virtual { public static final class VirtualDeviceParams.Builder { ctor public VirtualDeviceParams.Builder(); method @NonNull public android.companion.virtual.VirtualDeviceParams build(); - method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAllowedActivities(@Nullable java.util.Set<android.content.ComponentName>); - method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedActivities(@Nullable java.util.Set<android.content.ComponentName>); + method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAllowedActivities(@NonNull java.util.Set<android.content.ComponentName>); + method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedActivities(@NonNull java.util.Set<android.content.ComponentName>); method @NonNull @RequiresPermission(value=android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY, conditional=true) public android.companion.virtual.VirtualDeviceParams.Builder setLockState(int); method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setUsersWithMatchingAccounts(@NonNull java.util.Set<android.os.UserHandle>); } @@ -3035,6 +3038,7 @@ package android.content { field public static final String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED"; field public static final String ACTION_USER_SWITCHED = "android.intent.action.USER_SWITCHED"; field @RequiresPermission(android.Manifest.permission.START_VIEW_APP_FEATURES) public static final String ACTION_VIEW_APP_FEATURES = "android.intent.action.VIEW_APP_FEATURES"; + field @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public static final String ACTION_VIEW_SAFETY_CENTER_QS = "android.intent.action.VIEW_SAFETY_CENTER_QS"; field public static final String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST"; field public static final String CATEGORY_LEANBACK_SETTINGS = "android.intent.category.LEANBACK_SETTINGS"; field public static final String EXTRA_CALLING_PACKAGE = "android.intent.extra.CALLING_PACKAGE"; @@ -5908,16 +5912,16 @@ package android.location { method @IntRange(from=0, to=1023) public int getIssueOfDataClock(); method @IntRange(from=0, to=255) public int getIssueOfDataEphemeris(); method @Nullable public android.location.SatellitePvt.PositionEcef getPositionEcef(); - method @IntRange(from=0) public long getTimeOfClock(); - method @IntRange(from=0) public long getTimeOfEphemeris(); + method @IntRange(from=0) public long getTimeOfClockSeconds(); + method @IntRange(from=0) public long getTimeOfEphemerisSeconds(); method @FloatRange public double getTropoDelayMeters(); method @Nullable public android.location.SatellitePvt.VelocityEcef getVelocityEcef(); method public boolean hasIono(); method public boolean hasIssueOfDataClock(); method public boolean hasIssueOfDataEphemeris(); method public boolean hasPositionVelocityClockInfo(); - method public boolean hasTimeOfClock(); - method public boolean hasTimeOfEphemeris(); + method public boolean hasTimeOfClockSeconds(); + method public boolean hasTimeOfEphemerisSeconds(); method public boolean hasTropo(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt> CREATOR; @@ -5936,8 +5940,8 @@ package android.location { method @NonNull public android.location.SatellitePvt.Builder setIssueOfDataClock(@IntRange(from=0, to=1023) int); method @NonNull public android.location.SatellitePvt.Builder setIssueOfDataEphemeris(@IntRange(from=0, to=255) int); method @NonNull public android.location.SatellitePvt.Builder setPositionEcef(@NonNull android.location.SatellitePvt.PositionEcef); - method @NonNull public android.location.SatellitePvt.Builder setTimeOfClock(@IntRange(from=0) long); - method @NonNull public android.location.SatellitePvt.Builder setTimeOfEphemeris(@IntRange(from=0) int); + method @NonNull public android.location.SatellitePvt.Builder setTimeOfClockSeconds(@IntRange(from=0) long); + method @NonNull public android.location.SatellitePvt.Builder setTimeOfEphemerisSeconds(@IntRange(from=0) long); method @NonNull public android.location.SatellitePvt.Builder setTropoDelayMeters(@FloatRange(from=0.0f, to=100.0f) double); method @NonNull public android.location.SatellitePvt.Builder setVelocityEcef(@NonNull android.location.SatellitePvt.VelocityEcef); } @@ -6104,7 +6108,7 @@ package android.media { public class AudioManager { method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addAssistantServicesUids(@NonNull java.util.List<java.lang.Integer>); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addAssistantServicesUids(@NonNull int[]); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException; method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForCapturePresetChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener) throws java.lang.SecurityException; method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener) throws java.lang.SecurityException; @@ -6112,9 +6116,9 @@ package android.media { method public void clearAudioServerStateCallback(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean clearPreferredDevicesForCapturePreset(int); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); - method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<java.lang.Integer> getActiveAssistantServicesUids(); + method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getActiveAssistantServicesUids(); method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo); - method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<java.lang.Integer> getAssistantServicesUids(); + method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getAssistantServicesUids(); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies(); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups(); method @NonNull @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public android.media.AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull android.media.AudioFormat); @@ -6139,7 +6143,7 @@ package android.media { method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void registerMuteAwaitConnectionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.MuteAwaitConnectionCallback); method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeAssistantServicesUids(@NonNull java.util.List<java.lang.Integer>); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeAssistantServicesUids(@NonNull int[]); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForCapturePresetChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener); @@ -6147,7 +6151,7 @@ package android.media { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException; method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException; method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setActiveAssistantServiceUids(@NonNull java.util.List<java.lang.Integer>); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setActiveAssistantServiceUids(@NonNull int[]); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) long); method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int); @@ -8528,14 +8532,21 @@ package android.net { } public final class EthernetNetworkUpdateRequest implements android.os.Parcelable { - ctor public EthernetNetworkUpdateRequest(@NonNull android.net.StaticIpConfiguration, @NonNull android.net.NetworkCapabilities); method public int describeContents(); - method @NonNull public android.net.StaticIpConfiguration getIpConfig(); + method @NonNull public android.net.IpConfiguration getIpConfiguration(); method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkUpdateRequest> CREATOR; } + public static final class EthernetNetworkUpdateRequest.Builder { + ctor public EthernetNetworkUpdateRequest.Builder(); + ctor public EthernetNetworkUpdateRequest.Builder(@NonNull android.net.EthernetNetworkUpdateRequest); + method @NonNull public android.net.EthernetNetworkUpdateRequest build(); + method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setIpConfiguration(@NonNull android.net.IpConfiguration); + method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setNetworkCapabilities(@NonNull android.net.NetworkCapabilities); + } + public final class MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { ctor public MatchAllNetworkSpecifier(); method public int describeContents(); @@ -10318,6 +10329,7 @@ package android.provider { field public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native"; field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot"; field public static final String NAMESPACE_SCHEDULER = "scheduler"; + field public static final String NAMESPACE_SDK_SANDBOX = "sdk_sandbox"; field public static final String NAMESPACE_STATSD_JAVA = "statsd_java"; field public static final String NAMESPACE_STATSD_JAVA_BOOT = "statsd_java_boot"; field public static final String NAMESPACE_STATSD_NATIVE = "statsd_native"; diff --git a/core/api/test-current.txt b/core/api/test-current.txt index b752c4de22c7..22637ca95b9c 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1073,7 +1073,7 @@ package android.hardware { field public static final int DIALOG = 3; // 0x3 field public static final int OTHER = 5; // 0x5 field public static final int QS_TILE = 1; // 0x1 - field public static final int SAFETY_HUB = 6; // 0x6 + field public static final int SAFETY_CENTER = 6; // 0x6 field public static final int SETTINGS = 2; // 0x2 field public static final int SHELL = 4; // 0x4 } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 11663a52e6ae..bc979fc4af84 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -7416,7 +7416,6 @@ public class Activity extends ContextThemeWrapper } else { mDumpableContainer.listDumpables(prefix, writer); } - mDumpableContainer.listDumpables(prefix, writer); return; case DUMP_ARG_DUMP_DUMPABLE: if (args.length == 1) { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 61d186579f1b..64f0301fab22 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4469,12 +4469,6 @@ public final class ActivityThread extends ClientTransactionHandler // we are back active so skip it. unscheduleGcIdler(); - // To investigate "duplciate Application objects" bug (b/185177290) - if (UserHandle.myUserId() != UserHandle.getUserId(data.info.applicationInfo.uid)) { - Slog.wtf(TAG, "handleCreateService called with wrong appinfo UID: myUserId=" - + UserHandle.myUserId() + " appinfo.uid=" + data.info.applicationInfo.uid); - } - LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo, data.compatInfo); Service service = null; diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 99a523a0e18a..cf259e577a5a 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -160,6 +160,13 @@ public final class LoadedApk { private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices = new ArrayMap<>(); private AppComponentFactory mAppComponentFactory; + + /** + * We cache the instantiated application object for each package on this process here. + */ + @GuardedBy("sApplications") + private static final ArrayMap<String, Application> sApplications = new ArrayMap<>(4); + private final Object mLock = new Object(); Application getApplication() { @@ -1345,14 +1352,6 @@ public final class LoadedApk { return mResources; } - /** - * Used to investigate "duplicate app objects" bug (b/185177290). - * makeApplication() should only be called on the main thread, so no synchronization should - * be needed, but syncing anyway just in case. - */ - @GuardedBy("sApplicationCache") - private static final ArrayMap<String, Application> sApplicationCache = new ArrayMap<>(4); - @UnsupportedAppUsage public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) { @@ -1361,15 +1360,8 @@ public final class LoadedApk { } Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication"); - // For b/185177290. - final boolean wrongUser = - UserHandle.myUserId() != UserHandle.getUserId(mApplicationInfo.uid); - if (wrongUser) { - Slog.wtf(TAG, "makeApplication called with wrong appinfo UID: myUserId=" - + UserHandle.myUserId() + " appinfo.uid=" + mApplicationInfo.uid); - } - synchronized (sApplicationCache) { - final Application cached = sApplicationCache.get(mPackageName); + synchronized (sApplications) { + final Application cached = sApplications.get(mPackageName); if (cached != null) { // Looks like this is always happening for the system server, because // the LoadedApk created in systemMain() -> attach() isn't cached properly? @@ -1377,8 +1369,8 @@ public final class LoadedApk { Slog.wtf(TAG, "App instance already created for package=" + mPackageName + " instance=" + cached); } - // TODO Return the cached one, unles it's for the wrong user? - // For now, we just add WTF checks. + mApplication = cached; + return cached; } } @@ -1429,8 +1421,8 @@ public final class LoadedApk { } mActivityThread.mAllApplications.add(app); mApplication = app; - synchronized (sApplicationCache) { - sApplicationCache.put(mPackageName, app); + synchronized (sApplications) { + sApplications.put(mPackageName, app); } if (instrumentation != null) { diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 9dd206e21c44..7e0cea8921a4 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -9009,6 +9009,10 @@ public class Notification implements Parcelable * information that will replace the default values for the output switcher chip on the * media control, as well as an intent to use when the output switcher chip is tapped, * on devices where this is supported. + * <p> + * This method is intended for system applications to provide information and/or + * functionality that would otherwise be unavailable to the default output switcher because + * the media originated on a remote device. * * @param deviceName The name of the remote device to display * @param iconResource Icon resource representing the device diff --git a/core/java/android/app/admin/WifiSsidPolicy.aidl b/core/java/android/app/admin/WifiSsidPolicy.aidl new file mode 100644 index 000000000000..150705ddce62 --- /dev/null +++ b/core/java/android/app/admin/WifiSsidPolicy.aidl @@ -0,0 +1,20 @@ +/* + * 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.app.admin; + +parcelable WifiSsidPolicy;
\ No newline at end of file diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java index 45d0ad51da04..41b1a1feae80 100644 --- a/core/java/android/companion/virtual/VirtualDeviceParams.java +++ b/core/java/android/companion/virtual/VirtualDeviceParams.java @@ -20,9 +20,7 @@ import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.content.ComponentName; import android.os.Parcel; @@ -64,20 +62,43 @@ public final class VirtualDeviceParams implements Parcelable { */ public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1; + /** @hide */ + @IntDef(prefix = "ACTIVITY_POLICY_", + value = {ACTIVITY_POLICY_DEFAULT_ALLOWED, ACTIVITY_POLICY_DEFAULT_BLOCKED}) + @Retention(RetentionPolicy.SOURCE) + @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) + public @interface ActivityPolicy {} + + /** + * Indicates that activities are allowed by default on this virtual device, unless they are + * explicitly blocked by {@link Builder#setBlockedActivities}. + */ + public static final int ACTIVITY_POLICY_DEFAULT_ALLOWED = 0; + + /** + * Indicates that activities are blocked by default on this virtual device, unless they are + * allowed by {@link Builder#setAllowedActivities}. + */ + public static final int ACTIVITY_POLICY_DEFAULT_BLOCKED = 1; + private final int mLockState; private final ArraySet<UserHandle> mUsersWithMatchingAccounts; - @Nullable private final ArraySet<ComponentName> mAllowedActivities; - @Nullable private final ArraySet<ComponentName> mBlockedActivities; + @NonNull private final ArraySet<ComponentName> mAllowedActivities; + @NonNull private final ArraySet<ComponentName> mBlockedActivities; + @ActivityPolicy + private final int mDefaultActivityPolicy; private VirtualDeviceParams( @LockState int lockState, @NonNull Set<UserHandle> usersWithMatchingAccounts, - @Nullable Set<ComponentName> allowedActivities, - @Nullable Set<ComponentName> blockedActivities) { + @NonNull Set<ComponentName> allowedActivities, + @NonNull Set<ComponentName> blockedActivities, + @ActivityPolicy int defaultActivityPolicy) { mLockState = lockState; mUsersWithMatchingAccounts = new ArraySet<>(usersWithMatchingAccounts); mAllowedActivities = allowedActivities == null ? null : new ArraySet<>(allowedActivities); mBlockedActivities = blockedActivities == null ? null : new ArraySet<>(blockedActivities); + mDefaultActivityPolicy = defaultActivityPolicy; } @SuppressWarnings("unchecked") @@ -86,6 +107,7 @@ public final class VirtualDeviceParams implements Parcelable { mUsersWithMatchingAccounts = (ArraySet<UserHandle>) parcel.readArraySet(null); mAllowedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null); mBlockedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null); + mDefaultActivityPolicy = parcel.readInt(); } /** @@ -113,12 +135,10 @@ public final class VirtualDeviceParams implements Parcelable { * * @see Builder#setAllowedActivities(Set) */ - // Null and empty have different semantics - Null allows all activities to be streamed - @SuppressLint("NullableCollection") - @Nullable + @NonNull public Set<ComponentName> getAllowedActivities() { if (mAllowedActivities == null) { - return null; + return Collections.emptySet(); } return Collections.unmodifiableSet(mAllowedActivities); } @@ -129,16 +149,27 @@ public final class VirtualDeviceParams implements Parcelable { * * @see Builder#setBlockedActivities(Set) */ - // Allowing null to enforce that at most one of allowed / blocked activities can be non-null - @SuppressLint("NullableCollection") - @Nullable + @NonNull public Set<ComponentName> getBlockedActivities() { if (mBlockedActivities == null) { - return null; + return Collections.emptySet(); } return Collections.unmodifiableSet(mBlockedActivities); } + /** + * Returns {@link #ACTIVITY_POLICY_DEFAULT_ALLOWED} if activities are allowed to launch on this + * virtual device by default, or {@link #ACTIVITY_POLICY_DEFAULT_BLOCKED} if activities must be + * allowed by {@link Builder#setAllowedActivities} to launch here. + * + * @see Builder#setBlockedActivities + * @see Builder#setAllowedActivities + */ + @ActivityPolicy + public int getDefaultActivityPolicy() { + return mDefaultActivityPolicy; + } + @Override public int describeContents() { return 0; @@ -150,6 +181,7 @@ public final class VirtualDeviceParams implements Parcelable { dest.writeArraySet(mUsersWithMatchingAccounts); dest.writeArraySet(mAllowedActivities); dest.writeArraySet(mBlockedActivities); + dest.writeInt(mDefaultActivityPolicy); } @Override @@ -164,12 +196,15 @@ public final class VirtualDeviceParams implements Parcelable { return mLockState == that.mLockState && mUsersWithMatchingAccounts.equals(that.mUsersWithMatchingAccounts) && Objects.equals(mAllowedActivities, that.mAllowedActivities) - && Objects.equals(mBlockedActivities, that.mBlockedActivities); + && Objects.equals(mBlockedActivities, that.mBlockedActivities) + && mDefaultActivityPolicy == that.mDefaultActivityPolicy; } @Override public int hashCode() { - return Objects.hash(mLockState, mUsersWithMatchingAccounts); + return Objects.hash( + mLockState, mUsersWithMatchingAccounts, mAllowedActivities, mBlockedActivities, + mDefaultActivityPolicy); } @Override @@ -180,6 +215,7 @@ public final class VirtualDeviceParams implements Parcelable { + " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts + " mAllowedActivities=" + mAllowedActivities + " mBlockedActivities=" + mBlockedActivities + + " mDefaultActivityPolicy=" + mDefaultActivityPolicy + ")"; } @@ -202,8 +238,11 @@ public final class VirtualDeviceParams implements Parcelable { private @LockState int mLockState = LOCK_STATE_DEFAULT; private Set<UserHandle> mUsersWithMatchingAccounts; - @Nullable private Set<ComponentName> mBlockedActivities; - @Nullable private Set<ComponentName> mAllowedActivities; + @NonNull private Set<ComponentName> mBlockedActivities = Collections.emptySet(); + @NonNull private Set<ComponentName> mAllowedActivities = Collections.emptySet(); + @ActivityPolicy + private int mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED; + private boolean mDefaultActivityPolicyConfigured = false; /** * Sets the lock state of the device. The permission {@code ADD_ALWAYS_UNLOCKED_DISPLAY} @@ -248,53 +287,53 @@ public final class VirtualDeviceParams implements Parcelable { } /** - * Sets the activities allowed to be launched in the virtual device. If - * {@code allowedActivities} is non-null, all activities other than the ones in the set will - * be blocked from launching. + * Sets the activities allowed to be launched in the virtual device. Calling this method + * will cause {@link #getDefaultActivityPolicy()} to be + * {@link #ACTIVITY_POLICY_DEFAULT_BLOCKED}, meaning activities not in + * {@code allowedActivities} will be blocked from launching here. * - * <p>{@code allowedActivities} and the set in {@link #setBlockedActivities(Set)} cannot - * both be non-null at the same time. + * <p>This method must not be called if {@link #setBlockedActivities(Set)} has been called. * - * @throws IllegalArgumentException if {@link #setBlockedActivities(Set)} has been set to a - * non-null value. + * @throws IllegalArgumentException if {@link #setBlockedActivities(Set)} has been called. * * @param allowedActivities A set of activity {@link ComponentName} allowed to be launched * in the virtual device. */ - // Null and empty have different semantics - Null allows all activities to be streamed - @SuppressLint("NullableCollection") @NonNull - public Builder setAllowedActivities(@Nullable Set<ComponentName> allowedActivities) { - if (mBlockedActivities != null && allowedActivities != null) { + public Builder setAllowedActivities(@NonNull Set<ComponentName> allowedActivities) { + if (mDefaultActivityPolicyConfigured + && mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_BLOCKED) { throw new IllegalArgumentException( "Allowed activities and Blocked activities cannot both be set."); } + mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_BLOCKED; + mDefaultActivityPolicyConfigured = true; mAllowedActivities = allowedActivities; return this; } /** - * Sets the activities blocked from launching in the virtual device. If the {@code - * blockedActivities} is non-null, activities in the set are blocked from launching in the - * virtual device. + * Sets the activities blocked from launching in the virtual device. Calling this method + * will cause {@link #getDefaultActivityPolicy()} to be + * {@link #ACTIVITY_POLICY_DEFAULT_ALLOWED}, meaning activities are allowed to launch here + * unless they are in {@code blockedActivities}. * - * {@code blockedActivities} and the set in {@link #setAllowedActivities(Set)} cannot both - * be non-null at the same time. + * <p>This method must not be called if {@link #setAllowedActivities(Set)} has been called. * - * @throws IllegalArgumentException if {@link #setAllowedActivities(Set)} has been set to a - * non-null value. + * @throws IllegalArgumentException if {@link #setAllowedActivities(Set)} has been called. * * @param blockedActivities A set of {@link ComponentName} to be blocked launching from * virtual device. */ - // Allowing null to enforce that at most one of allowed / blocked activities can be non-null - @SuppressLint("NullableCollection") @NonNull - public Builder setBlockedActivities(@Nullable Set<ComponentName> blockedActivities) { - if (mAllowedActivities != null && blockedActivities != null) { + public Builder setBlockedActivities(@NonNull Set<ComponentName> blockedActivities) { + if (mDefaultActivityPolicyConfigured + && mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_ALLOWED) { throw new IllegalArgumentException( "Allowed activities and Blocked activities cannot both be set."); } + mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED; + mDefaultActivityPolicyConfigured = true; mBlockedActivities = blockedActivities; return this; } @@ -307,13 +346,12 @@ public final class VirtualDeviceParams implements Parcelable { if (mUsersWithMatchingAccounts == null) { mUsersWithMatchingAccounts = Collections.emptySet(); } - if (mAllowedActivities != null && mBlockedActivities != null) { - // Should never reach here because the setters block this as well. - throw new IllegalStateException( - "Allowed activities and Blocked activities cannot both be set."); - } - return new VirtualDeviceParams(mLockState, mUsersWithMatchingAccounts, - mAllowedActivities, mBlockedActivities); + return new VirtualDeviceParams( + mLockState, + mUsersWithMatchingAccounts, + mAllowedActivities, + mBlockedActivities, + mDefaultActivityPolicy); } } } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 0aa25ef97dd0..478befd9c26d 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2054,7 +2054,7 @@ public class Intent implements Parcelable, Cloneable { "android.intent.action.VIEW_PERMISSION_USAGE_FOR_PERIOD"; /** - * Activity action: Launch the Safety Hub UI. + * Activity action: Launch the Safety Center Quick Settings UI. * * <p> * Input: Nothing. @@ -2062,11 +2062,14 @@ public class Intent implements Parcelable, Cloneable { * <p> * Output: Nothing. * </p> + * + * @hide */ + @SystemApi @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) - public static final String ACTION_VIEW_SAFETY_HUB = - "android.intent.action.VIEW_SAFETY_HUB"; + public static final String ACTION_VIEW_SAFETY_CENTER_QS = + "android.intent.action.VIEW_SAFETY_CENTER_QS"; /** * Activity action: Launch UI to manage a default app. diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java index a3cc01c0adfb..0460e5831e33 100644 --- a/core/java/android/hardware/SensorPrivacyManager.java +++ b/core/java/android/hardware/SensorPrivacyManager.java @@ -136,9 +136,9 @@ public final class SensorPrivacyManager { public static final int OTHER = SensorPrivacyToggleSourceProto.OTHER; /** - * Constant for SAFETY_HUB. + * Constant for SAFETY_CENTER. */ - public static final int SAFETY_HUB = SensorPrivacyToggleSourceProto.SAFETY_HUB; + public static final int SAFETY_CENTER = SensorPrivacyToggleSourceProto.SAFETY_CENTER; /** * Source for toggling sensors @@ -151,7 +151,7 @@ public final class SensorPrivacyManager { DIALOG, SHELL, OTHER, - SAFETY_HUB + SAFETY_CENTER }) @Retention(RetentionPolicy.SOURCE) public @interface Source {} @@ -652,7 +652,7 @@ public final class SensorPrivacyManager { String packageName = mContext.getOpPackageName(); if (Objects.equals(packageName, mContext.getPackageManager().getPermissionControllerPackageName())) { - return Sources.SAFETY_HUB; + return Sources.SAFETY_CENTER; } return Sources.OTHER; } diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java index 779d931245c8..c51444cd31b6 100644 --- a/core/java/android/net/VpnManager.java +++ b/core/java/android/net/VpnManager.java @@ -108,7 +108,7 @@ public class VpnManager { * <ul> * <li>{@link #EXTRA_SESSION_KEY}, a {@code String} for the session key, as returned by * {@link #startProvisionedVpnProfileSession}. - * <li>{@link #EXTRA_TIMESTAMP}, a long for the timestamp at which the error occurred, + * <li>{@link #EXTRA_TIMESTAMP_MILLIS}, a long for the timestamp at which the error occurred, * in milliseconds since the epoch, as returned by * {@link java.lang.System#currentTimeMillis}. * <li>{@link #EXTRA_UNDERLYING_NETWORK}, a {@link Network} containing the underlying @@ -196,7 +196,7 @@ public class VpnManager { * This is a number of milliseconds since the epoch, suitable to be compared with * {@link java.lang.System#currentTimeMillis}. */ - public static final String EXTRA_TIMESTAMP = "android.net.extra.TIMESTAMP"; + public static final String EXTRA_TIMESTAMP_MILLIS = "android.net.extra.TIMESTAMP_MILLIS"; /** * Extra for the error class, as an {@code int}. diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 09cfb6e70cba..978e99d6c5c5 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -201,7 +201,7 @@ import java.util.function.Supplier; * The methods to use are {@link #writeFileDescriptor(FileDescriptor)}, * {@link #readFileDescriptor()}. * - * <h3>Untyped Containers</h3> + * <h3>Parcelable Containers</h3> * * <p>A final class of methods are for writing and reading standard Java * containers of arbitrary types. These all revolve around the @@ -213,6 +213,19 @@ import java.util.function.Supplier; * {@link #writeMap(Map)}, {@link #readMap(Map, ClassLoader)}, * {@link #writeSparseArray(SparseArray)}, * {@link #readSparseArray(ClassLoader)}. + * + * <h3>Restricted Parcelable Containers</h3> + * + * <p>A final class of methods are for reading standard Java containers of restricted types. + * These methods replace methods for reading containers of arbitrary types from previous section + * starting from Android {@link Build.VERSION_CODES#TIRAMISU}. The pairing writing methods are + * still the same from previous section. + * These methods accepts additional {@code clazz} parameters as the required types. + * The Restricted Parcelable container methods are {@link #readArray(ClassLoader, Class)}, + * {@link #readList(List, ClassLoader, Class)}, + * {@link #readArrayList(ClassLoader, Class)}, + * {@link #readMap(Map, ClassLoader, Class, Class)}, + * {@link #readSparseArray(ClassLoader, Class)}. */ public final class Parcel { @@ -3839,7 +3852,7 @@ public final class Parcel { */ @NonNull public <T> List<T> readParcelableList(@NonNull List<T> list, - @Nullable ClassLoader cl, @NonNull Class<T> clazz) { + @Nullable ClassLoader cl, @NonNull Class<? extends T> clazz) { Objects.requireNonNull(list); Objects.requireNonNull(clazz); return readParcelableListInternal(list, cl, clazz); @@ -3850,7 +3863,7 @@ public final class Parcel { */ @NonNull private <T> List<T> readParcelableListInternal(@NonNull List<T> list, - @Nullable ClassLoader cl, @Nullable Class<T> clazz) { + @Nullable ClassLoader cl, @Nullable Class<? extends T> clazz) { final int n = readInt(); if (n == -1) { list.clear(); diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 52b6944ba940..afd12835283b 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -407,6 +407,13 @@ public final class DeviceConfig { public static final String NAMESPACE_SCHEDULER = "scheduler"; /** + * Namespace for all SdkSandbox related features. + * @hide + */ + @SystemApi + public static final String NAMESPACE_SDK_SANDBOX = "sdk_sandbox"; + + /** * Namespace for settings statistics features. * * @hide diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 528156fb8f4e..8feff16c70a2 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9948,6 +9948,14 @@ public final class Settings { public static final String LOCKSCREEN_SHOW_CONTROLS = "lockscreen_show_controls"; /** + * Whether trivial home controls can be used without authentication + * + * @hide + */ + public static final String LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS = + "lockscreen_allow_trivial_controls"; + + /** * Whether wallet should be accessible from the lockscreen * * @hide @@ -9963,6 +9971,13 @@ public final class Settings { "lockscreen_use_double_line_clock"; /** + * Whether to show the vibrate icon in the Status Bar (default off) + * + * @hide + */ + public static final String STATUS_BAR_SHOW_VIBRATE_ICON = "status_bar_show_vibrate_icon"; + + /** * Specifies whether the web action API is enabled. * * @hide diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index db622d39b785..86707598255d 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -231,7 +231,7 @@ public class DreamService extends Service implements Window.Callback { * The default value for whether to show complications on the overlay. * @hide */ - public static final boolean DEFAULT_SHOW_COMPLICATIONS = true; + public static final boolean DEFAULT_SHOW_COMPLICATIONS = false; private final IDreamManager mDreamManager; private final Handler mHandler = new Handler(Looper.getMainLooper()); diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java index 4ac3178ecb4c..8604078b5ae5 100644 --- a/core/java/android/util/NtpTrustedTime.java +++ b/core/java/android/util/NtpTrustedTime.java @@ -81,7 +81,16 @@ public class NtpTrustedTime implements TrustedTime { /** Calculates and returns the age of this result. */ public long getAgeMillis() { - return SystemClock.elapsedRealtime() - mElapsedRealtimeMillis; + return getAgeMillis(SystemClock.elapsedRealtime()); + } + + /** + * Calculates and returns the age of this result relative to currentElapsedRealtimeMillis. + * + * @param currentElapsedRealtimeMillis - reference elapsed real time + */ + public long getAgeMillis(long currentElapsedRealtimeMillis) { + return currentElapsedRealtimeMillis - mElapsedRealtimeMillis; } @Override diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 55300b3fec36..91d5b208c237 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -1789,4 +1789,11 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall t.apply(); } } + + /** + * @hide + */ + public void syncNextFrame(Transaction t) { + mBlastBufferQueue.setSyncTransaction(t); + } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 34a13868f4d7..553c537d9b95 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -8226,9 +8226,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public void setAccessibilityPaneTitle(@Nullable CharSequence accessibilityPaneTitle) { if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) { + boolean currentPaneTitleEmpty = mAccessibilityPaneTitle == null; + boolean newPaneTitleEmpty = accessibilityPaneTitle == null; mAccessibilityPaneTitle = accessibilityPaneTitle; - notifyViewAccessibilityStateChangedIfNeeded( - AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE); + // Make explicitly important as nulled titles need to be important for DISAPPEARED + // events. + if (mAccessibilityPaneTitle != null + && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + } + if (currentPaneTitleEmpty) { + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED); + } else if (newPaneTitleEmpty) { + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); + } else { + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE); + } } } @@ -14168,9 +14184,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } // Changes to views with a pane title count as window state changes, as the pane title - // marks them as significant parts of the UI. + // marks them as significant parts of the UI. A visible view with a nulled title may send + // a disappeared event. if ((changeType != AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) - && isAccessibilityPane()) { + && (isAccessibilityPane() + || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) + && isAggregatedVisible())) { // If the pane isn't visible, content changed events are sufficient unless we're // reporting that the view just disappeared if ((isAggregatedVisible()) diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index feb17f54acd6..8bb7e677362c 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -195,6 +195,7 @@ import android.view.contentcapture.MainContentCaptureSession; import android.view.inputmethod.InputMethodManager; import android.widget.Scroller; import android.window.ClientWindowFrames; +import android.window.SurfaceSyncer; import android.window.WindowOnBackInvokedDispatcher; import com.android.internal.R; @@ -10873,4 +10874,71 @@ public final class ViewRootImpl implements ViewParent, IWindowSession getWindowSession() { return mWindowSession; } + + private void registerCallbacksForSync( + final SurfaceSyncer.SyncBufferCallback syncBufferCallback) { + if (!isHardwareEnabled()) { + // TODO: correctly handle when hardware disabled + syncBufferCallback.onBufferReady(null); + return; + } + + mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() { + @Override + public void onFrameDraw(long frame) { + } + + @Override + public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) { + if (DEBUG_BLAST) { + Log.d(mTag, + "Received frameDrawingCallback syncResult=" + syncResult + " frameNum=" + + frame + "."); + } + + final Transaction t = new Transaction(); + + // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or + // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up + // any blast sync or commit callback, and the code should directly call + // pendingDrawFinished. + if ((syncResult + & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) { + t.merge(mBlastBufferQueue.gatherPendingTransactions(frame)); + syncBufferCallback.onBufferReady(t); + return null; + } + + mBlastBufferQueue.setSyncTransaction(t); + if (DEBUG_BLAST) { + Log.d(mTag, "Setting up sync and frameCommitCallback"); + } + + return didProduceBuffer -> { + if (DEBUG_BLAST) { + Log.d(mTag, "Received frameCommittedCallback" + + " lastAttemptedDrawFrameNum=" + frame + + " didProduceBuffer=" + didProduceBuffer); + } + + // If frame wasn't drawn, clear out the next transaction so it doesn't affect + // the next draw attempt. The next transaction and transaction complete callback + // were only set for the current draw attempt. + if (!didProduceBuffer) { + mBlastBufferQueue.setSyncTransaction(null); + // Gather the transactions that were sent to mergeWithNextTransaction + // since the frame didn't draw on this vsync. It's possible the frame will + // draw later, but it's better to not be sync than to block on a frame that + // may never come. + t.merge(mBlastBufferQueue.gatherPendingTransactions(frame)); + } + + syncBufferCallback.onBufferReady(t); + }; + } + }); + } + + public final SurfaceSyncer.SyncTarget mSyncTarget = + syncBufferCallback -> registerCallbacksForSync(syncBufferCallback); } diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index cd8dd86b8e02..7e16531663d5 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -592,6 +592,11 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par /** * Change type for {@link #TYPE_WINDOW_STATE_CHANGED} event: * The node's pane title changed. + * <p> + * If this makes the pane appear, {@link #CONTENT_CHANGE_TYPE_PANE_APPEARED} is sent + * instead. If this makes the pane disappear, {@link #CONTENT_CHANGE_TYPE_PANE_DISAPPEARED} + * is sent. + * */ public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 0x00000008; diff --git a/core/java/android/window/ProxyOnBackInvokedDispatcher.java b/core/java/android/window/ProxyOnBackInvokedDispatcher.java index 4de977a91d05..cdbd0789a9c9 100644 --- a/core/java/android/window/ProxyOnBackInvokedDispatcher.java +++ b/core/java/android/window/ProxyOnBackInvokedDispatcher.java @@ -81,6 +81,10 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher { } synchronized (mLock) { mCallbacks.removeIf((p) -> p.first.equals(callback)); + if (mActualDispatcherOwner != null) { + mActualDispatcherOwner.getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback( + callback); + } } } diff --git a/core/java/android/window/SurfaceSyncer.java b/core/java/android/window/SurfaceSyncer.java new file mode 100644 index 000000000000..a5930757cae6 --- /dev/null +++ b/core/java/android/window/SurfaceSyncer.java @@ -0,0 +1,377 @@ +/* + * 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.window; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UiThread; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.util.SparseArray; +import android.view.SurfaceControl.Transaction; +import android.view.SurfaceView; +import android.view.View; + +import com.android.internal.annotations.GuardedBy; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + * Used to organize syncs for surfaces. + * + * The SurfaceSyncer allows callers to add desired syncs into a set and wait for them to all + * complete before getting a callback. The purpose of the Syncer is to be an accounting mechanism + * so each sync implementation doesn't need to handle it themselves. The Syncer class is used the + * following way. + * + * 1. {@link #setupSync(Runnable)} is called + * 2. {@link #addToSync(int, SyncTarget)} is called for every SyncTarget object that wants to be + * included in the sync. If the addSync is called for a View or SurfaceView it needs to be called + * on the UI thread. When addToSync is called, it's guaranteed that any UI updates that were + * requested before addToSync but after the last frame drew, will be included in the sync. + * 3. {@link #markSyncReady(int)} should be called when all the {@link SyncTarget}s have been added + * to the SyncSet. Now the SyncSet is closed and no more SyncTargets can be added to it. + * 4. The SyncSet will gather the data for each SyncTarget using the steps described below. When + * all the SyncTargets have finished, the syncRequestComplete will be invoked and the transaction + * will either be applied or sent to the caller. In most cases, only the SurfaceSyncer should be + * handling the Transaction object directly. However, there are some cases where the framework + * needs to send the Transaction elsewhere, like in ViewRootImpl, so that option is provided. + * + * The following is what happens within the {@link SyncSet} + * 1. Each SyncableTarget will get a {@link SyncTarget#onReadyToSync} callback that contains + * a {@link SyncBufferCallback}. + * 2. Each {@link SyncTarget} needs to invoke {@link SyncBufferCallback#onBufferReady(Transaction)}. + * This makes sure the SyncSet knows when the SyncTarget is complete, allowing the SyncSet to get + * the Transaction that contains the buffer. + * 3. When the final SyncBufferCallback finishes for the SyncSet, the syncRequestComplete Consumer + * will be invoked with the transaction that contains all information requested in the sync. This + * could include buffers and geometry changes. The buffer update will include the UI changes that + * were requested for the View. + * + * @hide + */ +public class SurfaceSyncer { + private static final String TAG = "SurfaceSyncer"; + private static final boolean DEBUG = false; + + private static Supplier<Transaction> sTransactionFactory = Transaction::new; + + private final Object mSyncSetLock = new Object(); + @GuardedBy("mSyncSetLock") + private final SparseArray<SyncSet> mSyncSets = new SparseArray<>(); + @GuardedBy("mSyncSetLock") + private int mIdCounter = 0; + + /** + * @hide + */ + public static void setTransactionFactory(Supplier<Transaction> transactionFactory) { + sTransactionFactory = transactionFactory; + } + + /** + * Starts a sync and will automatically apply the final, merged transaction. + * + * @param onComplete The runnable that is invoked when the sync has completed. This will run on + * the same thread that the sync was started on. + * @return The syncId for the newly created sync. + * @see #setupSync(Consumer) + */ + public int setupSync(@Nullable Runnable onComplete) { + Handler handler = new Handler(Looper.myLooper()); + return setupSync(transaction -> { + transaction.apply(); + handler.post(onComplete); + }); + } + + /** + * Starts a sync. + * + * @param syncRequestComplete The complete callback that contains the syncId and transaction + * with all the sync data merged. + * @return The syncId for the newly created sync. + * @hide + * @see #setupSync(Runnable) + */ + public int setupSync(@NonNull Consumer<Transaction> syncRequestComplete) { + synchronized (mSyncSetLock) { + mIdCounter++; + if (DEBUG) { + Log.d(TAG, "setupSync " + mIdCounter); + } + SyncSet syncSet = new SyncSet(mIdCounter, syncRequestComplete); + mSyncSets.put(mIdCounter, syncSet); + return mIdCounter; + } + } + + /** + * Mark the sync set as ready to complete. No more data can be added to the specified syncId. + * Once the sync set is marked as ready, it will be able to complete once all Syncables in the + * set have completed their sync + * + * @param syncId The syncId to mark as ready. + */ + public void markSyncReady(int syncId) { + SyncSet syncSet; + synchronized (mSyncSetLock) { + syncSet = mSyncSets.get(syncId); + mSyncSets.remove(syncId); + } + if (syncSet == null) { + Log.e(TAG, "Failed to find syncSet for syncId=" + syncId); + return; + } + syncSet.markSyncReady(); + } + + /** + * Add a SurfaceView to a sync set. This is different than {@link #addToSync(int, View)} because + * it requires the caller to notify the start and finish drawing in order to sync. + * + * @param syncId The syncId to add an entry to. + * @param surfaceView The SurfaceView to add to the sync. + * @param frameCallbackConsumer The callback that's invoked to allow the caller to notify the + * Syncer when the SurfaceView has started drawing and finished. + * + * @return true if the SurfaceView was successfully added to the SyncSet, false otherwise. + */ + @UiThread + public boolean addToSync(int syncId, SurfaceView surfaceView, + Consumer<SurfaceViewFrameCallback> frameCallbackConsumer) { + return addToSync(syncId, new SurfaceViewSyncTarget(surfaceView, frameCallbackConsumer)); + } + + /** + * Add a View's rootView to a sync set. + * + * @param syncId The syncId to add an entry to. + * @param view The view where the root will be add to the sync set + * + * @return true if the View was successfully added to the SyncSet, false otherwise. + */ + @UiThread + public boolean addToSync(int syncId, @NonNull View view) { + return addToSync(syncId, view.getViewRootImpl().mSyncTarget); + } + + /** + * Add a {@link SyncTarget} to a sync set. The sync set will wait for all + * SyncableSurfaces to complete before notifying. + * + * @param syncId The syncId to add an entry to. + * @param syncTarget A SyncableSurface that implements how to handle syncing + * buffers. + * + * @return true if the SyncTarget was successfully added to the SyncSet, false otherwise. + */ + public boolean addToSync(int syncId, @NonNull SyncTarget syncTarget) { + SyncSet syncSet = getAndValidateSyncSet(syncId); + if (syncSet == null) { + return false; + } + if (DEBUG) { + Log.d(TAG, "addToSync id=" + syncId); + } + syncSet.addSyncableSurface(syncTarget); + return true; + } + + /** + * Add a transaction to a specific sync so it can be merged along with the frames from the + * Syncables in the set. This is so the caller can add arbitrary transaction info that will be + * applied at the same time as the buffers + * @param syncId The syncId where the transaction will be merged to. + * @param t The transaction to merge in the sync set. + */ + public void addTransactionToSync(int syncId, Transaction t) { + SyncSet syncSet = getAndValidateSyncSet(syncId); + if (syncSet != null) { + syncSet.addTransactionToSync(t); + } + } + + private SyncSet getAndValidateSyncSet(int syncId) { + SyncSet syncSet; + synchronized (mSyncSetLock) { + syncSet = mSyncSets.get(syncId); + } + if (syncSet == null) { + Log.e(TAG, "Failed to find sync for id=" + syncId); + return null; + } + return syncSet; + } + + /** + * A SyncTarget that can be added to a sync set. + */ + public interface SyncTarget { + /** + * Called when the Syncable is ready to begin handing a sync request. When invoked, the + * implementor is required to call {@link SyncBufferCallback#onBufferReady(Transaction)} + * and {@link SyncBufferCallback#onBufferReady(Transaction)} in order for this Syncable + * to be marked as complete. + * + * @param syncBufferCallback A SyncBufferCallback that the caller must invoke onBufferReady + */ + void onReadyToSync(SyncBufferCallback syncBufferCallback); + } + + /** + * Interface so the SurfaceSyncer can know when it's safe to start and when everything has been + * completed. The caller should invoke the calls when the rendering has started and finished a + * frame. + */ + public interface SyncBufferCallback { + /** + * Invoked when the transaction contains the buffer and is ready to sync. + * + * @param t The transaction that contains the buffer to be synced. This can be null if + * there's nothing to sync + */ + void onBufferReady(@Nullable Transaction t); + } + + /** + * Class that collects the {@link SyncTarget}s and notifies when all the surfaces have + * a frame ready. + */ + private static class SyncSet { + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private final Set<Integer> mPendingSyncs = new HashSet<>(); + @GuardedBy("mLock") + private final Transaction mTransaction = sTransactionFactory.get(); + @GuardedBy("mLock") + private boolean mSyncReady; + + private final int mSyncId; + private final Consumer<Transaction> mSyncRequestCompleteCallback; + + private SyncSet(int syncId, Consumer<Transaction> syncRequestComplete) { + mSyncId = syncId; + mSyncRequestCompleteCallback = syncRequestComplete; + } + + void addSyncableSurface(SyncTarget syncTarget) { + SyncBufferCallback syncBufferCallback = new SyncBufferCallback() { + @Override + public void onBufferReady(Transaction t) { + synchronized (mLock) { + if (t != null) { + mTransaction.merge(t); + } + mPendingSyncs.remove(hashCode()); + checkIfSyncIsComplete(); + } + } + }; + + synchronized (mLock) { + mPendingSyncs.add(syncBufferCallback.hashCode()); + } + syncTarget.onReadyToSync(syncBufferCallback); + } + + void markSyncReady() { + synchronized (mLock) { + mSyncReady = true; + checkIfSyncIsComplete(); + } + } + + @GuardedBy("mLock") + private void checkIfSyncIsComplete() { + if (!mSyncReady || !mPendingSyncs.isEmpty()) { + if (DEBUG) { + Log.d(TAG, "Syncable is not complete. mSyncReady=" + mSyncReady + + " mPendingSyncs=" + mPendingSyncs.size()); + } + return; + } + + if (DEBUG) { + Log.d(TAG, "Successfully finished sync id=" + mSyncId); + } + mSyncRequestCompleteCallback.accept(mTransaction); + } + + /** + * Add a Transaction to this sync set. This allows the caller to provide other info that + * should be synced with the buffers. + */ + void addTransactionToSync(Transaction t) { + synchronized (mLock) { + mTransaction.merge(t); + } + } + } + + /** + * Wrapper class to help synchronize SurfaceViews + */ + private static class SurfaceViewSyncTarget implements SyncTarget { + private final SurfaceView mSurfaceView; + private final Consumer<SurfaceViewFrameCallback> mFrameCallbackConsumer; + + SurfaceViewSyncTarget(SurfaceView surfaceView, + Consumer<SurfaceViewFrameCallback> frameCallbackConsumer) { + mSurfaceView = surfaceView; + mFrameCallbackConsumer = frameCallbackConsumer; + } + + @Override + public void onReadyToSync(SyncBufferCallback syncBufferCallback) { + Transaction mTransaction = sTransactionFactory.get(); + mFrameCallbackConsumer.accept(new SurfaceViewFrameCallback() { + @Override + public void onFrameStarted() { + mSurfaceView.syncNextFrame(mTransaction); + } + + @Override + public void onFrameComplete() { + syncBufferCallback.onBufferReady(mTransaction); + } + }); + } + } + + /** + * A frame callback that is used to synchronize SurfaceViews. The owner of the SurfaceView must + * implement onFrameStarted and onFrameComplete when trying to sync the SurfaceView. This is to + * ensure the sync knows when the frame is ready to add to the sync. + */ + public interface SurfaceViewFrameCallback { + /** + * Called when the SurfaceView is going to render a frame + */ + void onFrameStarted(); + + /** + * Called when the SurfaceView has finished rendering a frame. + */ + void onFrameComplete(); + } +} diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java index 0503c406c287..94e5ea960f4f 100644 --- a/core/java/android/window/WindowOnBackInvokedDispatcher.java +++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java @@ -76,9 +76,9 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { /** Detaches the dispatcher instance from its window. */ public void detachFromWindow() { + clear(); mWindow = null; mWindowSession = null; - clear(); } // TODO: Take an Executor for the callback to run on. @@ -165,21 +165,32 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { } else { int priority = mAllCallbacks.get(callback); mWindowSession.setOnBackInvokedCallback( - mWindow, new OnBackInvokedCallbackWrapper(callback, priority), priority); + mWindow, new OnBackInvokedCallbackWrapper(callback), priority); } } catch (RemoteException e) { Log.e(TAG, "Failed to set OnBackInvokedCallback to WM. Error: " + e); } } - private class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub { + @Override + public OnBackInvokedCallback getTopCallback() { + if (mAllCallbacks.isEmpty()) { + return null; + } + for (Integer priority : mOnBackInvokedCallbacks.descendingKeySet()) { + ArrayList<OnBackInvokedCallback> callbacks = mOnBackInvokedCallbacks.get(priority); + if (!callbacks.isEmpty()) { + return callbacks.get(callbacks.size() - 1); + } + } + return null; + } + + private static class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub { private final OnBackInvokedCallback mCallback; - private final @Priority int mPriority; - OnBackInvokedCallbackWrapper( - @NonNull OnBackInvokedCallback callback, @Priority int priority) { + OnBackInvokedCallbackWrapper(@NonNull OnBackInvokedCallback callback) { mCallback = callback; - mPriority = priority; } @NonNull @@ -188,18 +199,17 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { } @Override - public void onBackStarted() throws RemoteException { + public void onBackStarted() { Handler.getMain().post(() -> mCallback.onBackStarted()); } @Override - public void onBackProgressed(BackEvent backEvent) - throws RemoteException { + public void onBackProgressed(BackEvent backEvent) { Handler.getMain().post(() -> mCallback.onBackProgressed(backEvent)); } @Override - public void onBackCancelled() throws RemoteException { + public void onBackCancelled() { Handler.getMain().post(() -> mCallback.onBackCancelled()); } @@ -209,20 +219,6 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { } } - @Override - public OnBackInvokedCallback getTopCallback() { - if (mAllCallbacks.isEmpty()) { - return null; - } - for (Integer priority : mOnBackInvokedCallbacks.descendingKeySet()) { - ArrayList<OnBackInvokedCallback> callbacks = mOnBackInvokedCallbacks.get(priority); - if (!callbacks.isEmpty()) { - return callbacks.get(callbacks.size() - 1); - } - } - return null; - } - /** * Returns if the legacy back behavior should be used. * diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index dc55c0512941..90b272ccd127 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -2712,10 +2712,10 @@ static jint android_media_AudioSystem_getDevicesForRoleAndCapturePreset(JNIEnv * return AUDIO_JAVA_SUCCESS; } -static jint -android_media_AudioSystem_getDevicesForAttributes(JNIEnv *env, jobject thiz, - jobject jaa, jobjectArray jDeviceArray) -{ +static jint android_media_AudioSystem_getDevicesForAttributes(JNIEnv *env, jobject thiz, + jobject jaa, + jobjectArray jDeviceArray, + jboolean forVolume) { const jsize maxResultSize = env->GetArrayLength(jDeviceArray); // the JNI is always expected to provide us with an array capable of holding enough // devices i.e. the most we ever route a track to. This is preferred over receiving an ArrayList @@ -2734,7 +2734,7 @@ android_media_AudioSystem_getDevicesForAttributes(JNIEnv *env, jobject thiz, AudioDeviceTypeAddrVector devices; jStatus = check_AudioSystem_Command( - AudioSystem::getDevicesForAttributes(*(paa.get()), &devices)); + AudioSystem::getDevicesForAttributes(*(paa.get()), &devices, forVolume)); if (jStatus != NO_ERROR) { return jStatus; } @@ -3045,7 +3045,7 @@ static const JNINativeMethod gMethods[] = {"getDevicesForRoleAndCapturePreset", "(IILjava/util/List;)I", (void *)android_media_AudioSystem_getDevicesForRoleAndCapturePreset}, {"getDevicesForAttributes", - "(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAttributes;)I", + "(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAttributes;Z)I", (void *)android_media_AudioSystem_getDevicesForAttributes}, {"setUserIdDeviceAffinities", "(I[I[Ljava/lang/String;)I", (void *)android_media_AudioSystem_setUserIdDeviceAffinities}, diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 095641864030..68025a8ba0e4 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -62,6 +62,7 @@ namespace android { +using gui::CaptureArgs; using gui::FocusRequest; static void doThrowNPE(JNIEnv* env) { diff --git a/core/proto/android/hardware/sensorprivacy.proto b/core/proto/android/hardware/sensorprivacy.proto index 97870a16da2b..9359528b613b 100644 --- a/core/proto/android/hardware/sensorprivacy.proto +++ b/core/proto/android/hardware/sensorprivacy.proto @@ -128,7 +128,7 @@ message SensorPrivacyToggleSourceProto { DIALOG = 3; SHELL = 4; OTHER = 5; - SAFETY_HUB = 6; + SAFETY_CENTER = 6; } // Source for which sensor privacy was toggled. diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 5ac30de631c5..c2cb57d84b34 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1207,13 +1207,13 @@ <!-- Display low battery warning when battery level dips to this value. Also, the battery stats are flushed to disk when we hit this level. --> - <integer name="config_criticalBatteryWarningLevel">5</integer> + <integer name="config_criticalBatteryWarningLevel">10</integer> <!-- Shutdown if the battery temperature exceeds (this value * 0.1) Celsius. --> <integer name="config_shutdownBatteryTemperature">680</integer> <!-- Display low battery warning when battery level dips to this value --> - <integer name="config_lowBatteryWarningLevel">15</integer> + <integer name="config_lowBatteryWarningLevel">20</integer> <!-- The default suggested battery % at which we enable battery saver automatically. --> <integer name="config_lowBatteryAutoTriggerDefaultLevel">15</integer> diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index bccd2b6529ac..29eb0c0365b3 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -62,8 +62,9 @@ <!-- View id for the action of text editor inside of an extracted text {@link InputMethodService#onCreateExtractTextView IME extract view}. --> <item type="id" name="inputExtractAction" /> - <!-- View id for the accessories of text editor inside of an extracted text - {@link InputMethodService#onCreateExtractTextView IME extract view}. --> + <!-- View id for the accessories (such as the extracted input action button) of text editor + inside of an extracted text {@link InputMethodService#onCreateExtractTextView IME extract + view}. This layout must contain the {@link #inputExtractAction}. --> <item type="id" name="inputExtractAccessories" /> <item type="id" name="selectAll" /> <item type="id" name="cut" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index e41aa45e0a44..e64756119478 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -197,7 +197,7 @@ <string name="ThreeWCMmi">Three way calling</string> <string name="RuacMmi">Rejection of undesired annoying calls</string> <string name="CndMmi">Calling number delivery</string> - <string name="DndMmi" translatable="false">Priority mode</string> + <string name="DndMmi">Do not disturb</string> <!-- Displayed to confirm to the user that caller ID will be restricted on the next call as usual. --> <string name="CLIRDefaultOnNextCallOn">Caller ID defaults to restricted. Next call: Restricted</string> @@ -2036,9 +2036,9 @@ <string name="permdesc_bindCarrierServices">Allows the holder to bind to carrier services. Should never be needed for normal apps.</string> <!-- Title of an application permission, for applications that wish to access notification policy. --> - <string name="permlab_access_notification_policy" translatable="false">access Priority mode</string> + <string name="permlab_access_notification_policy">access Do Not Disturb</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permdesc_access_notification_policy" translatable="false">Allows the app to read and write Priority mode configuration.</string> + <string name="permdesc_access_notification_policy">Allows the app to read and write Do Not Disturb configuration.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_startViewPermissionUsage">start view permission usage</string> @@ -5302,7 +5302,7 @@ <string name="zen_mode_forever">Until you turn off</string> <!-- Zen mode condition: no exit criteria, includes the name of the feature for emphasis. [CHAR LIMIT=NONE] --> - <string name="zen_mode_forever_dnd" translatable="false">Until you turn off Priority mode</string> + <string name="zen_mode_forever_dnd">Until you turn off Do Not Disturb</string> <!-- Zen mode active automatic rule name separator. [CHAR LIMIT=NONE] --> <string name="zen_mode_rule_name_combination"><xliff:g id="first" example="Weeknights">%1$s</xliff:g> / <xliff:g id="rest" example="Meetings">%2$s</xliff:g></string> @@ -5311,7 +5311,7 @@ <string name="toolbar_collapse_description">Collapse</string> <!-- Zen mode - feature name. [CHAR LIMIT=40] --> - <string name="zen_mode_feature_name" translatable="false">Priority mode</string> + <string name="zen_mode_feature_name">Do not disturb</string> <!-- Zen mode - downtime legacy feature name. [CHAR LIMIT=40] --> <string name="zen_mode_downtime_feature_name">Downtime</string> @@ -5745,14 +5745,14 @@ <!-- Title for the notification channel notifying user of settings system changes. [CHAR LIMIT=NONE] --> <string name="notification_channel_system_changes">System changes</string> - <!-- Title for the notification channel notifying user of priority mode system changes (i.e. Priority mode has changed). [CHAR LIMIT=NONE] --> - <string name="notification_channel_do_not_disturb" translatable="false">Priority mode</string> - <!-- Title of notification indicating Priority mode visual interruption settings have changed when upgrading to P --> - <string name="zen_upgrade_notification_visd_title" translatable="false">New: Priority mode is hiding notifications</string> + <!-- Title for the notification channel notifying user of do not disturb system changes (i.e. Do Not Disturb has changed). [CHAR LIMIT=NONE] --> + <string name="notification_channel_do_not_disturb">Do Not Disturb</string> + <!-- Title of notification indicating do not disturb visual interruption settings have changed when upgrading to P --> + <string name="zen_upgrade_notification_visd_title">New: Do Not Disturb is hiding notifications</string> <!-- Content of notification indicating users can tap on the notification to go to dnd behavior settings --> <string name="zen_upgrade_notification_visd_content">Tap to learn more and change.</string> - <!-- Title of notification indicating priority mode settings have changed when upgrading to P --> - <string name="zen_upgrade_notification_title" translatable="false">Priority mode has changed</string> + <!-- Title of notification indicating do not disturb settings have changed when upgrading to P --> + <string name="zen_upgrade_notification_title">Do Not Disturb has changed</string> <!-- Content of notification indicating users can tap on the notification to go to dnd behavior settings --> <string name="zen_upgrade_notification_content">Tap to check what\'s blocked.</string> @@ -5793,7 +5793,7 @@ <!-- Label of notification action button to learn more about the enhanced notifications [CHAR LIMIT=20] --> <string name="nas_upgrade_notification_learn_more_action">Learn more</string> <!-- Content of notification learn more dialog about the enhanced notifications [CHAR LIMIT=NONE] --> - <string name="nas_upgrade_notification_learn_more_content" translatable="false">Enhanced notifications replaced Android Adaptive Notifications in Android 12. This feature shows suggested actions and replies, and organizes your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls, and control Priority mode.</string> + <string name="nas_upgrade_notification_learn_more_content">Enhanced notifications replaced Android Adaptive Notifications in Android 12. This feature shows suggested actions and replies, and organizes your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls, and control Do Not Disturb.</string> <!-- Dynamic mode battery saver strings --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 60a3398c93e6..e543034b6974 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1291,6 +1291,7 @@ <java-symbol type="array" name="vendor_required_apps_managed_profile" /> <java-symbol type="array" name="vendor_required_apps_managed_device" /> <java-symbol type="array" name="vendor_required_attestation_certificates" /> + <java-symbol type="string" name="vendor_required_attestation_revocation_list_url" /> <java-symbol type="array" name="vendor_disallowed_apps_managed_user" /> <java-symbol type="array" name="vendor_disallowed_apps_managed_profile" /> <java-symbol type="array" name="vendor_disallowed_apps_managed_device" /> diff --git a/core/res/res/values/vendor_required_attestation_certificates.xml b/core/res/res/values/vendor_required_attestation_certificates.xml index ce5660f433ff..ff7313ed1b4d 100644 --- a/core/res/res/values/vendor_required_attestation_certificates.xml +++ b/core/res/res/values/vendor_required_attestation_certificates.xml @@ -29,4 +29,10 @@ --> <string-array translatable="false" name="vendor_required_attestation_certificates"> </string-array> + + <!-- Url to mapping of revoked certificates' hex encoded serial numbers. Example format + can be found at: + https://developer.android.com/training/articles/security-key-attestation#certificate_status + --> + <string translatable="false" name="vendor_required_attestation_revocation_list_url"></string> </resources> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 2d2c03bf2215..3c64cf55eb50 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -20,13 +20,6 @@ This XML file declares which signature|privileged permissions should be granted applications that come with the platform --> <permissions> - <privapp-permissions package="android.ext.services"> - <permission name="android.permission.PROVIDE_RESOLVER_RANKER_SERVICE" /> - <permission name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE" /> - <permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" /> - <permission name="android.permission.INTERACT_ACROSS_USERS" /> - </privapp-permissions> - <!-- Needed for Build.getSerial(), which is used to send a unique number for serial, per HUIG. --> <privapp-permissions package="android.car.usb.handler"> <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index 91615fe05417..f01457bc4c95 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -84,6 +84,7 @@ public class PipTransition extends PipTransitionController { private final Optional<SplitScreenController> mSplitScreenOptional; private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS; private Transitions.TransitionFinishCallback mFinishCallback; + private SurfaceControl.Transaction mFinishTransaction; private final Rect mExitDestinationBounds = new Rect(); @Nullable private IBinder mExitTransition; @@ -166,6 +167,7 @@ public class PipTransition extends PipTransitionController { if (mFinishCallback != null) { mFinishCallback.onTransitionFinished(null, null); mFinishCallback = null; + mFinishTransaction = null; throw new RuntimeException("Previous callback not called, aborting exit PIP."); } @@ -267,7 +269,8 @@ public class PipTransition extends PipTransitionController { public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, @Nullable SurfaceControl.Transaction tx) { - if (isInPipDirection(direction)) { + final boolean enteringPip = isInPipDirection(direction); + if (enteringPip) { mPipTransitionState.setTransitionState(ENTERED_PIP); } // If there is an expected exit transition, then the exit will be "merged" into this @@ -279,6 +282,20 @@ public class PipTransition extends PipTransitionController { if (tx != null) { wct.setBoundsChangeTransaction(taskInfo.token, tx); } + final SurfaceControl leash = mPipOrganizer.getSurfaceControl(); + final int displayRotation = taskInfo.getConfiguration().windowConfiguration + .getDisplayRotation(); + if (enteringPip && mInFixedRotation && mEndFixedRotation != displayRotation + && leash != null && leash.isValid()) { + // Launcher may update the Shelf height during the animation, which will update the + // destination bounds. Because this is in fixed rotation, We need to make sure the + // finishTransaction is using the updated bounds in the display rotation. + final Rect displayBounds = mPipBoundsState.getDisplayBounds(); + final Rect finishBounds = new Rect(destinationBounds); + rotateBounds(finishBounds, displayBounds, mEndFixedRotation, displayRotation); + mSurfaceTransactionHelper.crop(mFinishTransaction, leash, finishBounds); + } + mFinishTransaction = null; mFinishCallback.onTransitionFinished(wct, null /* callback */); mFinishCallback = null; } @@ -290,6 +307,7 @@ public class PipTransition extends PipTransitionController { if (mFinishCallback == null) return; mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */); mFinishCallback = null; + mFinishTransaction = null; } @Override @@ -336,6 +354,7 @@ public class PipTransition extends PipTransitionController { mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo()); finishCallback.onTransitionFinished(wct, wctCB); }; + mFinishTransaction = finishTransaction; // Check if it is Shell rotation. if (Transitions.SHELL_TRANSITIONS_ROTATION) { @@ -526,6 +545,7 @@ public class PipTransition extends PipTransitionController { if (mFinishCallback != null) { mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */); mFinishCallback = null; + mFinishTransaction = null; throw new RuntimeException("Previous callback not called, aborting entering PIP."); } @@ -549,6 +569,7 @@ public class PipTransition extends PipTransitionController { mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP); mFinishCallback = finishCallback; + mFinishTransaction = finishTransaction; final int endRotation = mInFixedRotation ? mEndFixedRotation : enterPip.getEndRotation(); return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(), startTransaction, finishTransaction, enterPip.getStartRotation(), diff --git a/location/java/android/location/SatellitePvt.java b/location/java/android/location/SatellitePvt.java index f140c68b19db..f3e15084d730 100644 --- a/location/java/android/location/SatellitePvt.java +++ b/location/java/android/location/SatellitePvt.java @@ -144,8 +144,8 @@ public final class SatellitePvt implements Parcelable { private final ClockInfo mClockInfo; private final double mIonoDelayMeters; private final double mTropoDelayMeters; - private final long mTimeOfClock; - private final long mTimeOfEphemeris; + private final long mTimeOfClockSeconds; + private final long mTimeOfEphemerisSeconds; private final int mIssueOfDataClock; private final int mIssueOfDataEphemeris; @EphemerisSource @@ -457,8 +457,8 @@ public final class SatellitePvt implements Parcelable { @Nullable ClockInfo clockInfo, double ionoDelayMeters, double tropoDelayMeters, - long timeOfClock, - long timeOfEphemeris, + long timeOfClockSeconds, + long timeOfEphemerisSeconds, int issueOfDataClock, int issueOfDataEphemeris, @EphemerisSource int ephemerisSource) { @@ -468,8 +468,8 @@ public final class SatellitePvt implements Parcelable { mClockInfo = clockInfo; mIonoDelayMeters = ionoDelayMeters; mTropoDelayMeters = tropoDelayMeters; - mTimeOfClock = timeOfClock; - mTimeOfEphemeris = timeOfEphemeris; + mTimeOfClockSeconds = timeOfClockSeconds; + mTimeOfEphemerisSeconds = timeOfEphemerisSeconds; mIssueOfDataClock = issueOfDataClock; mIssueOfDataEphemeris = issueOfDataEphemeris; mEphemerisSource = ephemerisSource; @@ -545,31 +545,31 @@ public final class SatellitePvt implements Parcelable { } /** - * Time of Clock. + * Time of Clock in seconds. * * <p>The value is in seconds since GPS epoch, regardless of the constellation. * * <p>The value is not encoded as in GPS ICD200 documentation. * - * <p>This field is valid if {@link #hasTimeOfClock()} is true. + * <p>This field is valid if {@link #hasTimeOfClockSeconds()} is true. */ @IntRange(from = 0) - public long getTimeOfClock() { - return mTimeOfClock; + public long getTimeOfClockSeconds() { + return mTimeOfClockSeconds; } /** - * Time of ephemeris. + * Time of ephemeris in seconds. * * <p>The value is in seconds since GPS epoch, regardless of the constellation. * * <p>The value is not encoded as in GPS ICD200 documentation. * - * <p>This field is valid if {@link #hasTimeOfEphemeris()} is true. + * <p>This field is valid if {@link #hasTimeOfEphemerisSeconds()} is true. */ @IntRange(from = 0) - public long getTimeOfEphemeris() { - return mTimeOfEphemeris; + public long getTimeOfEphemerisSeconds() { + return mTimeOfEphemerisSeconds; } /** @@ -607,13 +607,13 @@ public final class SatellitePvt implements Parcelable { return (mFlags & HAS_ISSUE_OF_DATA_EPHEMERIS) != 0; } - /** Returns {@code true} if {@link #getTimeOfClock()} ()} is valid. */ - public boolean hasTimeOfClock() { + /** Returns {@code true} if {@link #getTimeOfClockSeconds()} ()} is valid. */ + public boolean hasTimeOfClockSeconds() { return (mFlags & HAS_TIME_OF_CLOCK) != 0; } - /** Returns {@code true} if {@link #getTimeOfEphemeris()} is valid. */ - public boolean hasTimeOfEphemeris() { + /** Returns {@code true} if {@link #getTimeOfEphemerisSeconds()} is valid. */ + public boolean hasTimeOfEphemerisSeconds() { return (mFlags & HAS_TIME_OF_EPHEMERIS) != 0; } @@ -671,8 +671,8 @@ public final class SatellitePvt implements Parcelable { parcel.writeParcelable(mClockInfo, flags); parcel.writeDouble(mIonoDelayMeters); parcel.writeDouble(mTropoDelayMeters); - parcel.writeLong(mTimeOfClock); - parcel.writeLong(mTimeOfEphemeris); + parcel.writeLong(mTimeOfClockSeconds); + parcel.writeLong(mTimeOfEphemerisSeconds); parcel.writeInt(mIssueOfDataClock); parcel.writeInt(mIssueOfDataEphemeris); parcel.writeInt(mEphemerisSource); @@ -687,8 +687,8 @@ public final class SatellitePvt implements Parcelable { + ", ClockInfo=" + mClockInfo + ", IonoDelayMeters=" + mIonoDelayMeters + ", TropoDelayMeters=" + mTropoDelayMeters - + ", TimeOfClock=" + mTimeOfClock - + ", TimeOfEphemeris=" + mTimeOfEphemeris + + ", TimeOfClockSeconds=" + mTimeOfClockSeconds + + ", TimeOfEphemerisSeconds=" + mTimeOfEphemerisSeconds + ", IssueOfDataClock=" + mIssueOfDataClock + ", IssueOfDataEphemeris=" + mIssueOfDataEphemeris + ", EphemerisSource=" + mEphemerisSource @@ -709,8 +709,8 @@ public final class SatellitePvt implements Parcelable { @Nullable private ClockInfo mClockInfo; private double mIonoDelayMeters; private double mTropoDelayMeters; - private long mTimeOfClock; - private long mTimeOfEphemeris; + private long mTimeOfClockSeconds; + private long mTimeOfEphemerisSeconds; private int mIssueOfDataClock; private int mIssueOfDataEphemeris; @EphemerisSource @@ -796,13 +796,13 @@ public final class SatellitePvt implements Parcelable { * * <p>The value is not encoded as in GPS ICD200 documentation. * - * @param timeOfClock time of clock (seconds) + * @param timeOfClockSeconds time of clock (seconds) * @return builder object */ @NonNull - public Builder setTimeOfClock(@IntRange(from = 0) long timeOfClock) { - Preconditions.checkArgumentNonnegative(timeOfClock); - mTimeOfClock = timeOfClock; + public Builder setTimeOfClockSeconds(@IntRange(from = 0) long timeOfClockSeconds) { + Preconditions.checkArgumentNonnegative(timeOfClockSeconds); + mTimeOfClockSeconds = timeOfClockSeconds; mFlags = (byte) (mFlags | HAS_TIME_OF_CLOCK); return this; } @@ -814,13 +814,13 @@ public final class SatellitePvt implements Parcelable { * * <p>The value is not encoded as in GPS ICD200 documentation. * - * @param timeOfEphemeris time of ephemeris (seconds) + * @param timeOfEphemerisSeconds time of ephemeris (seconds) * @return builder object */ @NonNull - public Builder setTimeOfEphemeris(@IntRange(from = 0) int timeOfEphemeris) { - Preconditions.checkArgumentNonnegative(timeOfEphemeris); - mTimeOfEphemeris = timeOfEphemeris; + public Builder setTimeOfEphemerisSeconds(@IntRange(from = 0) long timeOfEphemerisSeconds) { + Preconditions.checkArgumentNonnegative(timeOfEphemerisSeconds); + mTimeOfEphemerisSeconds = timeOfEphemerisSeconds; mFlags = (byte) (mFlags | HAS_TIME_OF_EPHEMERIS); return this; } @@ -879,7 +879,8 @@ public final class SatellitePvt implements Parcelable { @NonNull public SatellitePvt build() { return new SatellitePvt(mFlags, mPositionEcef, mVelocityEcef, mClockInfo, - mIonoDelayMeters, mTropoDelayMeters, mTimeOfClock, mTimeOfEphemeris, + mIonoDelayMeters, mTropoDelayMeters, mTimeOfClockSeconds, + mTimeOfEphemerisSeconds, mIssueOfDataClock, mIssueOfDataEphemeris, mEphemerisSource); } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 6e695e68fbf2..6c99a0734e3e 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -91,7 +91,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; /** * AudioManager provides access to volume and ringer mode control. @@ -8349,100 +8348,97 @@ public class AudioManager { } /** - * Add UID's that can be considered as assistant. + * Add UIDs that can be considered as assistant. * - * @param assistantUids UID's of the services that can be considered as assistant. + * @param assistantUids UIDs of the services that can be considered as assistant. * * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public void addAssistantServicesUids(@NonNull List<Integer> assistantUids) { + public void addAssistantServicesUids(@NonNull int[] assistantUids) { try { - getService().addAssistantServicesUids(assistantUids.stream() - .mapToInt(Integer::intValue).toArray()); + getService().addAssistantServicesUids(assistantUids); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Remove UID's that can be considered as assistant. + * Remove UIDs that can be considered as assistant. * - * @param assistantUids UID'S of the services that should be remove. + * @param assistantUids UIDs of the services that should be remove. * * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public void removeAssistantServicesUids(@NonNull List<Integer> assistantUids) { + public void removeAssistantServicesUids(@NonNull int[] assistantUids) { try { - getService().removeAssistantServicesUids(assistantUids.stream() - .mapToInt(Integer::intValue).toArray()); + getService().removeAssistantServicesUids(assistantUids); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Get the list of assistants UIDs that been added with the - * {@link #addAssistantServicesUids(List)} (List)} and not yet removed with - * {@link #removeAssistantServicesUids(List)} + * Get the assistants UIDs that been added with the + * {@link #addAssistantServicesUids(int[])} and not yet removed with + * {@link #removeAssistantServicesUids(int[])} * - * @return list of assistants UID's + * @return array of assistants UIDs * * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public @NonNull List<Integer> getAssistantServicesUids() { + public @NonNull int[] getAssistantServicesUids() { try { int[] uids = getService().getAssistantServicesUids(); - return Arrays.stream(uids).boxed().collect(Collectors.toList()); + return Arrays.copyOf(uids, uids.length); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Sets UID's that can be considered as active assistant. Calling the API with a new list will - * overwrite previous list. If the list of UIDs is empty then no UID will be considered active. - * In this manner calling the API with an empty list will remove all UID's previously set. + * Sets UIDs that can be considered as active assistant. Calling the API with a new array will + * overwrite previous UIDs. If the array of UIDs is empty then no UID will be considered active. + * In this manner calling the API with an empty array will remove all UIDs previously set. * - * @param assistantUids UID'S of the services that can be considered active assistant. Can be - * an empty list, for this no UID will be considered active. + * @param assistantUids UIDs of the services that can be considered active assistant. Can be + * an empty array, for this no UID will be considered active. * * <p> Note that during audio service crash reset and after boot up the list of active assistant - * UID's will be reset to an empty list (i.e. no UID will be considered as an active assistant). + * UIDs will be reset to an empty list (i.e. no UID will be considered as an active assistant). * Just after user switch the list of active assistant will also reset to empty. * * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public void setActiveAssistantServiceUids(@NonNull List<Integer> assistantUids) { + public void setActiveAssistantServiceUids(@NonNull int[] assistantUids) { try { - getService().setActiveAssistantServiceUids(assistantUids.stream() - .mapToInt(Integer::intValue).toArray()); + getService().setActiveAssistantServiceUids(assistantUids); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Get the list of active assistant UIDs last set with the - * {@link #setActiveAssistantServiceUids(List)} + * Get active assistant UIDs last set with the + * {@link #setActiveAssistantServiceUids(int[])} * - * @return list of active assistants UID's + * @return array of active assistants UIDs * * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public @NonNull List<Integer> getActiveAssistantServicesUids() { + public @NonNull int[] getActiveAssistantServicesUids() { try { int[] uids = getService().getActiveAssistantServiceUids(); - return Arrays.stream(uids).boxed().collect(Collectors.toList()); + return Arrays.copyOf(uids, uids.length); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 6cacebb433a6..210f3e5e4499 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -1668,13 +1668,14 @@ public class AudioSystem * otherwise (typically one device, except for duplicated paths). */ public static @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes( - @NonNull AudioAttributes attributes) { + @NonNull AudioAttributes attributes, boolean forVolume) { Objects.requireNonNull(attributes); final AudioDeviceAttributes[] devices = new AudioDeviceAttributes[MAX_DEVICE_ROUTING]; - final int res = getDevicesForAttributes(attributes, devices); + final int res = getDevicesForAttributes(attributes, devices, forVolume); final ArrayList<AudioDeviceAttributes> routeDevices = new ArrayList<>(); if (res != SUCCESS) { - Log.e(TAG, "error " + res + " in getDevicesForAttributes for " + attributes); + Log.e(TAG, "error " + res + " in getDevicesForAttributes attributes: " + attributes + + " forVolume: " + forVolume); return routeDevices; } @@ -1693,7 +1694,8 @@ public class AudioSystem private static final int MAX_DEVICE_ROUTING = 4; private static native int getDevicesForAttributes(@NonNull AudioAttributes aa, - @NonNull AudioDeviceAttributes[] devices); + @NonNull AudioDeviceAttributes[] devices, + boolean forVolume); /** @hide returns true if master mono is enabled. */ public static native boolean getMasterMono(); diff --git a/packages/CompanionDeviceManager/res/color/selector.xml b/packages/CompanionDeviceManager/res/color/selector.xml index fda827d7f9c8..56e5dca0f72f 100644 --- a/packages/CompanionDeviceManager/res/color/selector.xml +++ b/packages/CompanionDeviceManager/res/color/selector.xml @@ -16,5 +16,5 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:color="@android:color/darker_gray"/> <!-- pressed --> - <item android:color="@android:color/white"/> + <item android:color="?android:attr/colorBackground"/> </selector>
\ No newline at end of file diff --git a/packages/CompanionDeviceManager/res/drawable/dialog_background.xml b/packages/CompanionDeviceManager/res/drawable/dialog_background.xml index ef7052d56a44..a017f4167907 100644 --- a/packages/CompanionDeviceManager/res/drawable/dialog_background.xml +++ b/packages/CompanionDeviceManager/res/drawable/dialog_background.xml @@ -16,7 +16,7 @@ <inset xmlns:android="http://schemas.android.com/apk/res/android"> <shape android:shape="rectangle"> - <corners android:radius="@*android:dimen/config_dialogCornerRadius" /> + <corners android:radius="?android:attr/dialogCornerRadius" /> <solid android:color="?android:attr/colorBackground" /> </shape> </inset> diff --git a/packages/CompanionDeviceManager/res/values/themes.xml b/packages/CompanionDeviceManager/res/values/themes.xml index 8559ef64f2c9..72404322c25e 100644 --- a/packages/CompanionDeviceManager/res/values/themes.xml +++ b/packages/CompanionDeviceManager/res/values/themes.xml @@ -17,9 +17,7 @@ <resources> <style name="ChooserActivity" - parent="@style/Theme.AppCompat.Light.Dialog"> - <item name="windowActionBar">false</item> - <item name="windowNoTitle">true</item> + parent="@android:style/Theme.DeviceDefault.Light.Dialog"> <item name="*android:windowFixedHeightMajor">100%</item> <item name="*android:windowFixedHeightMinor">100%</item> <item name="android:windowBackground">@android:color/transparent</item> diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java index a6a8fcf9af62..ae0c8ccdf006 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java @@ -49,7 +49,7 @@ import android.view.View; import android.widget.Button; import android.widget.TextView; -import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.FragmentActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -59,7 +59,7 @@ import java.util.List; * A CompanionDevice activity response for showing the available * nearby devices to be associated with. */ -public class CompanionDeviceActivity extends AppCompatActivity { +public class CompanionDeviceActivity extends FragmentActivity { private static final boolean DEBUG = false; private static final String TAG = CompanionDeviceActivity.class.getSimpleName(); diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java index e879e40247cf..a6269711055a 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -27,13 +28,13 @@ import java.util.Objects; @SystemApi public final class EthernetNetworkUpdateRequest implements Parcelable { @NonNull - private final StaticIpConfiguration mIpConfig; + private final IpConfiguration mIpConfig; @NonNull private final NetworkCapabilities mNetworkCapabilities; @NonNull - public StaticIpConfiguration getIpConfig() { - return new StaticIpConfiguration(mIpConfig); + public IpConfiguration getIpConfiguration() { + return new IpConfiguration(mIpConfig); } @NonNull @@ -41,20 +42,75 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { return new NetworkCapabilities(mNetworkCapabilities); } - public EthernetNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig, + private EthernetNetworkUpdateRequest(@NonNull final IpConfiguration ipConfig, @NonNull final NetworkCapabilities networkCapabilities) { Objects.requireNonNull(ipConfig); Objects.requireNonNull(networkCapabilities); - mIpConfig = new StaticIpConfiguration(ipConfig); + mIpConfig = new IpConfiguration(ipConfig); mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); } private EthernetNetworkUpdateRequest(@NonNull final Parcel source) { Objects.requireNonNull(source); - mIpConfig = StaticIpConfiguration.CREATOR.createFromParcel(source); + mIpConfig = IpConfiguration.CREATOR.createFromParcel(source); mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source); } + /** + * Builder used to create {@link EthernetNetworkUpdateRequest} objects. + */ + public static final class Builder { + @Nullable + private IpConfiguration mBuilderIpConfig; + @Nullable + private NetworkCapabilities mBuilderNetworkCapabilities; + + public Builder(){} + + /** + * Constructor to populate the builder's values with an already built + * {@link EthernetNetworkUpdateRequest}. + * @param request the {@link EthernetNetworkUpdateRequest} to populate with. + */ + public Builder(@NonNull final EthernetNetworkUpdateRequest request) { + Objects.requireNonNull(request); + mBuilderIpConfig = new IpConfiguration(request.mIpConfig); + mBuilderNetworkCapabilities = new NetworkCapabilities(request.mNetworkCapabilities); + } + + /** + * Set the {@link IpConfiguration} to be used with the {@code Builder}. + * @param ipConfig the {@link IpConfiguration} to set. + * @return The builder to facilitate chaining. + */ + @NonNull + public Builder setIpConfiguration(@NonNull final IpConfiguration ipConfig) { + Objects.requireNonNull(ipConfig); + mBuilderIpConfig = new IpConfiguration(ipConfig); + return this; + } + + /** + * Set the {@link NetworkCapabilities} to be used with the {@code Builder}. + * @param nc the {@link NetworkCapabilities} to set. + * @return The builder to facilitate chaining. + */ + @NonNull + public Builder setNetworkCapabilities(@NonNull final NetworkCapabilities nc) { + Objects.requireNonNull(nc); + mBuilderNetworkCapabilities = new NetworkCapabilities(nc); + return this; + } + + /** + * Build {@link EthernetNetworkUpdateRequest} return the current update request. + */ + @NonNull + public EthernetNetworkUpdateRequest build() { + return new EthernetNetworkUpdateRequest(mBuilderIpConfig, mBuilderNetworkCapabilities); + } + } + @Override public String toString() { return "EthernetNetworkUpdateRequest{" @@ -68,7 +124,7 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { if (o == null || getClass() != o.getClass()) return false; EthernetNetworkUpdateRequest that = (EthernetNetworkUpdateRequest) o; - return Objects.equals(that.getIpConfig(), mIpConfig) + return Objects.equals(that.getIpConfiguration(), mIpConfig) && Objects.equals(that.getNetworkCapabilities(), mNetworkCapabilities); } diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 014a033a4c01..da0381b68278 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1311,8 +1311,8 @@ <!-- Do not disturb: Label for button in enable zen dialog that will turn on zen mode. [CHAR LIMIT=30] --> <string name="zen_mode_enable_dialog_turn_on">Turn on</string> - <!-- Priority mode: Title for the Priority mode dialog to turn on Priority mode. [CHAR LIMIT=50]--> - <string name="zen_mode_settings_turn_on_dialog_title" translatable="false">Turn on Priority mode</string> + <!-- Do not disturb: Title for the Do not Disturb dialog to turn on Do not disturb. [CHAR LIMIT=50]--> + <string name="zen_mode_settings_turn_on_dialog_title">Turn on Do Not Disturb</string> <!-- Sound: Summary for the Do not Disturb option when there is no automatic rules turned on. [CHAR LIMIT=NONE]--> <string name="zen_mode_settings_summary_off">Never</string> <!--[CHAR LIMIT=40] Zen Interruption level: Priority. --> diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 8e35ee96b691..c7673aa98797 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -193,8 +193,10 @@ public class SecureSettings { Settings.Secure.NOTIFICATION_BUBBLES, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, + Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, Settings.Secure.LOCKSCREEN_SHOW_WALLET, Settings.Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER, Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, + Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON }; } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index 5f549fd05e1a..42aa2053e1a4 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -152,9 +152,11 @@ public class SecureSettingsValidators { VALIDATORS.put(Secure.CONTROLS_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.POWER_MENU_LOCKED_SHOW_CONTENT, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCKSCREEN_SHOW_CONTROLS, BOOLEAN_VALIDATOR); + VALIDATORS.put(Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCKSCREEN_SHOW_WALLET, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, BOOLEAN_VALIDATOR); + VALIDATORS.put(Secure.STATUS_BAR_SHOW_VIBRATE_ICON, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.DOZE_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.DOZE_ALWAYS_ON, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.DOZE_PICK_UP_GESTURE, BOOLEAN_VALIDATOR); diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 4b1d00bb18e3..7f8b2f51754c 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -154,7 +154,7 @@ <!-- Needed for WallpaperManager.clear in ImageWallpaper.updateWallpaperLocked --> <uses-permission android:name="android.permission.SET_WALLPAPER"/> - <!-- Needed for WallpaperManager.getWallpaperDimAmount in StatusBar.updateTheme --> + <!-- Needed for WallpaperManager.getWallpaperDimAmount in CentralSurfaces.updateTheme --> <uses-permission android:name="android.permission.SET_WALLPAPER_DIM_AMOUNT"/> <!-- Wifi Display --> diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags index 6352f81b4474..c97ebe8d5559 100644 --- a/packages/SystemUI/proguard.flags +++ b/packages/SystemUI/proguard.flags @@ -3,7 +3,7 @@ -keep class com.android.systemui.recents.OverviewProxyRecentsImpl -keep class com.android.systemui.statusbar.car.CarStatusBar --keep class com.android.systemui.statusbar.phone.StatusBar +-keep class com.android.systemui.statusbar.phone.CentralSurfaces -keep class com.android.systemui.statusbar.tv.TvStatusBar -keep class com.android.systemui.car.CarSystemUIFactory -keep class com.android.systemui.SystemUIFactory diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml index 31d848d3e4d5..16a1d944c4d3 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml @@ -26,6 +26,7 @@ systemui:layout_constraintStart_toStartOf="parent" systemui:layout_constraintEnd_toEndOf="parent" systemui:layout_constraintTop_toTopOf="parent" + android:layout_marginHorizontal="@dimen/status_view_margin_horizontal" android:layout_width="0dp" android:layout_height="wrap_content"> <LinearLayout diff --git a/packages/SystemUI/res/drawable-mdpi/dream_preview_back_arrow.png b/packages/SystemUI/res/drawable-mdpi/dream_preview_back_arrow.png Binary files differnew file mode 100644 index 000000000000..2c2f94ebe750 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/dream_preview_back_arrow.png diff --git a/packages/SystemUI/res/drawable-xhdpi/dream_preview_back_arrow.png b/packages/SystemUI/res/drawable-xhdpi/dream_preview_back_arrow.png Binary files differnew file mode 100644 index 000000000000..881b9afdc3d2 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/dream_preview_back_arrow.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/dream_preview_back_arrow.png b/packages/SystemUI/res/drawable-xxhdpi/dream_preview_back_arrow.png Binary files differnew file mode 100644 index 000000000000..6063b42ef221 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/dream_preview_back_arrow.png diff --git a/packages/SystemUI/res/drawable/notif_dungeon_bg_gradient.xml b/packages/SystemUI/res/drawable/notif_dungeon_bg_gradient.xml deleted file mode 100644 index e456e2965d21..000000000000 --- a/packages/SystemUI/res/drawable/notif_dungeon_bg_gradient.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2020 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> -<shape - xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - <gradient - android:angle="90" - android:startColor="#ff000000" - android:endColor="#00000000" - android:type="linear" /> -</shape> diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_preview.xml b/packages/SystemUI/res/layout/dream_overlay_complication_preview.xml index 37b8365996fd..ca5c4996cddb 100644 --- a/packages/SystemUI/res/layout/dream_overlay_complication_preview.xml +++ b/packages/SystemUI/res/layout/dream_overlay_complication_preview.xml @@ -24,6 +24,5 @@ android:shadowColor="@color/keyguard_shadow_color" android:shadowRadius="?attr/shadowRadius" android:gravity="center_vertical" - android:drawableStart="@drawable/ic_arrow_back" - android:drawablePadding="@dimen/dream_overlay_complication_preview_icon_padding" - android:drawableTint="@android:color/white"/> + android:drawableStart="@drawable/dream_preview_back_arrow" + android:drawablePadding="@dimen/dream_overlay_complication_preview_icon_padding"/> diff --git a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml index 813787e8f9d0..1cbc3c284874 100644 --- a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml +++ b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml @@ -29,7 +29,6 @@ android:layout_width="@dimen/dream_overlay_notification_indicator_size" android:layout_height="@dimen/dream_overlay_notification_indicator_size" android:visibility="gone" - android:contentDescription="@string/dream_overlay_status_bar_notification_indicator" app:dotColor="@android:color/white" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" @@ -68,7 +67,7 @@ android:layout_width="@dimen/dream_overlay_status_bar_icon_size" android:layout_height="match_parent" android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin" - android:src="@drawable/ic_remove_circle" + android:src="@drawable/ic_qs_dnd_on" android:tint="@android:color/white" android:visibility="gone" android:contentDescription="@string/dream_overlay_status_bar_priority_mode" /> diff --git a/packages/SystemUI/res/layout/foreground_service_dungeon.xml b/packages/SystemUI/res/layout/foreground_service_dungeon.xml deleted file mode 100644 index d4e98e217213..000000000000 --- a/packages/SystemUI/res/layout/foreground_service_dungeon.xml +++ /dev/null @@ -1,61 +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. - --> - -<com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/foreground_service_dungeon" - android:layout_width="@dimen/qs_panel_width" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal|bottom" - android:visibility="visible" -> - <LinearLayout - android:layout_height="wrap_content" - android:layout_width="match_parent" - android:orientation="vertical" - android:gravity="bottom" - android:visibility="visible" - android:background="@drawable/notif_dungeon_bg_gradient" - > - - <!-- divider view --> - <View - android:layout_width="match_parent" - android:layout_height="1dp" - android:background="@color/GM2_grey_200" - android:visibility="visible" - /> - - <TextView - android:id="@+id/dungeon_title" - android:layout_height="48dp" - android:layout_width="match_parent" - android:padding="8dp" - android:text="Apps active in background" - android:textColor="@color/GM2_grey_200" - /> - - <!-- List containing the actual foreground service notifications --> - <LinearLayout - android:id="@+id/entry_list" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="bottom" - android:orientation="vertical" > - </LinearLayout> - - </LinearLayout> -</com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView> diff --git a/packages/SystemUI/res/layout/foreground_service_dungeon_row.xml b/packages/SystemUI/res/layout/foreground_service_dungeon_row.xml deleted file mode 100644 index a6f1638a1d89..000000000000 --- a/packages/SystemUI/res/layout/foreground_service_dungeon_row.xml +++ /dev/null @@ -1,43 +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. - --> - -<com.android.systemui.statusbar.notification.row.DungeonRow - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/foreground_service_dungeon_row" - android:layout_width="match_parent" - android:layout_height="48dp" - android:padding="8dp" - android:clickable="true" - android:orientation="horizontal" > - - <com.android.systemui.statusbar.StatusBarIconView - android:id="@+id/icon" - android:layout_width="24dp" - android:layout_height="24dp" - android:padding="4dp" /> - - <TextView - android:id="@+id/app_name" - android:layout_width="0dp" - android:layout_weight="1" - android:layout_height="wrap_content" - android:paddingStart="4dp" - android:gravity="center_vertical" - android:layout_gravity="center_vertical" - android:textColor="@color/GM2_grey_200" - /> - -</com.android.systemui.statusbar.notification.row.DungeonRow> diff --git a/packages/SystemUI/res/layout/media_projection_dialog_title.xml b/packages/SystemUI/res/layout/media_projection_dialog_title.xml deleted file mode 100644 index b9e39dae13dc..000000000000 --- a/packages/SystemUI/res/layout/media_projection_dialog_title.xml +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright 2019, The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - xmlns:android="http://schemas.android.com/apk/res/android" - android:theme="@style/Theme.SystemUI.MediaProjectionAlertDialog" - android:paddingStart="?android:attr/dialogPreferredPadding" - android:paddingEnd="?android:attr/dialogPreferredPadding" - android:orientation="vertical"> - <ImageView - android:id="@+id/dialog_icon" - android:src="@drawable/ic_media_projection_permission" - android:layout_height="24dp" - android:layout_width="24dp" - android:layout_marginTop="18dp" - android:layout_marginBottom="12dp" - android:layout_gravity="center_horizontal" /> - <TextView - android:id="@+id/dialog_title" - android:gravity="center" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:textSize="20sp" - android:textColor="?android:attr/textColorPrimary" - android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Title" /> -</LinearLayout> diff --git a/packages/SystemUI/res/layout/notif_half_shelf.xml b/packages/SystemUI/res/layout/notif_half_shelf.xml index b2ff46e0de29..8ba1ff38fd63 100644 --- a/packages/SystemUI/res/layout/notif_half_shelf.xml +++ b/packages/SystemUI/res/layout/notif_half_shelf.xml @@ -27,7 +27,7 @@ <LinearLayout android:id="@+id/half_shelf" - android:layout_width="@dimen/qs_panel_width" + android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:gravity="bottom" diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index c7910afc73fc..e4706e263a0f 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -94,10 +94,11 @@ <FrameLayout android:id="@+id/qs_frame" android:layout="@layout/qs_panel" - android:layout_width="@dimen/qs_panel_width" + android:layout_width="0dp" android:layout_height="0dp" android:clipToPadding="false" android:clipChildren="false" + android:layout_marginHorizontal="@dimen/notification_panel_margin_horizontal" systemui:viewType="com.android.systemui.plugins.qs.QS" systemui:layout_constraintStart_toStartOf="parent" systemui:layout_constraintEnd_toEndOf="parent" @@ -115,8 +116,9 @@ <com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout android:id="@+id/notification_stack_scroller" android:layout_marginTop="@dimen/notification_panel_margin_top" - android:layout_width="@dimen/notification_panel_width" + android:layout_width="0dp" android:layout_height="match_parent" + android:layout_marginHorizontal="@dimen/notification_panel_margin_horizontal" android:layout_marginBottom="@dimen/notification_panel_margin_bottom" android:importantForAccessibility="no" systemui:layout_constraintStart_toStartOf="parent" diff --git a/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml b/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml index 65f55d0d5903..8a2310bc307d 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml @@ -19,7 +19,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/plugin_frame" android:theme="@style/Theme.SystemUI.QuickSettings" - android:layout_width="@dimen/qs_panel_width" + android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="@dimen/notification_side_paddings" diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml index c37c804caaa8..4f95811b21b3 100644 --- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml @@ -42,4 +42,9 @@ the shade (in alpha) --> <dimen name="lockscreen_shade_scrim_transition_distance">200dp</dimen> + <!-- Distance that the full shade transition takes in order for media to fully transition to + the shade --> + <dimen name="lockscreen_shade_media_transition_distance">200dp</dimen> + + <dimen name="notification_panel_margin_horizontal">12dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml index da2403a96afa..56dc4a1026b5 100644 --- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp-port/dimens.xml @@ -15,7 +15,8 @@ ~ limitations under the License. --> <resources> - <!-- Size of the panel of large phones on portrait. This shouldn't fill, but have some padding on the side --> - <dimen name="notification_panel_width">504dp</dimen> - + <dimen name="notification_panel_margin_horizontal">60dp</dimen> + <dimen name="status_view_margin_horizontal">62dp</dimen> + <dimen name="keyguard_clock_top_margin">40dp</dimen> + <dimen name="keyguard_status_view_bottom_margin">40dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml index e897f75470a9..71c195896051 100644 --- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml +++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml @@ -22,4 +22,6 @@ <dimen name="notification_panel_margin_bottom">56dp</dimen> <dimen name="keyguard_split_shade_top_margin">72dp</dimen> + + <dimen name="notification_panel_margin_horizontal">24dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml new file mode 100644 index 000000000000..594df346fab1 --- /dev/null +++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources> + <dimen name="status_view_margin_horizontal">124dp</dimen> + <dimen name="notification_panel_margin_horizontal">120dp</dimen> + <dimen name="keyguard_clock_top_margin">80dp</dimen> + <dimen name="keyguard_status_view_bottom_margin">80dp</dimen> +</resources> diff --git a/packages/SystemUI/res/values-w650dp-land/dimens.xml b/packages/SystemUI/res/values-w650dp-land/dimens.xml deleted file mode 100644 index 97b6da1ac6a7..000000000000 --- a/packages/SystemUI/res/values-w650dp-land/dimens.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2020 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> -<resources> - <!-- Standard notification width + gravity --> - <dimen name="notification_panel_width">-1px</dimen> <!-- match_parent --> -</resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 2de8324a506a..83e6a54e272b 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -74,12 +74,12 @@ <!-- The default tiles to display in QuickSettings --> <string name="quick_settings_tiles_default" translatable="false"> - internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,custom(com.android.permissioncontroller/.permission.service.SafetyHubQsTileService) + internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,custom(com.android.permissioncontroller/.permission.service.SafetyCenterQsTileService) </string> <!-- The component name of the Safety Quick Settings Tile --> <string name="safety_quick_settings_tile" translatable="false"> - custom(com.android.permissioncontroller/.permission.service.SafetyHubQsTileService) + custom(com.android.permissioncontroller/.permission.service.SafetyCenterQsTileService) </string> <!-- The minimum number of tiles to display in QuickSettings --> @@ -487,6 +487,9 @@ space --> <bool name="config_showBatteryEstimateQSBH">false</bool> + <!-- Whether to show a severe low battery dialog. --> + <bool name="config_severe_battery_dialog">false</bool> + <!-- A path similar to frameworks/base/core/res/res/values/config.xml config_mainBuiltInDisplayCutout that describes a path larger than the exact path of a display cutout. If present as well as config_enableDisplayCutoutProtection is set to true, then diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 92bc8642b75c..65c17b9028e1 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -388,13 +388,10 @@ <dimen name="split_shade_notifications_scrim_margin_bottom">0dp</dimen> - <dimen name="notification_panel_width">@dimen/match_parent</dimen> + <dimen name="notification_panel_margin_horizontal">0dp</dimen> <dimen name="brightness_mirror_height">48dp</dimen> - <!-- The width of the panel that holds the quick settings. --> - <dimen name="qs_panel_width">@dimen/notification_panel_width</dimen> - <dimen name="volume_dialog_panel_transparent_padding_right">8dp</dimen> <dimen name="volume_dialog_panel_transparent_padding">20dp</dimen> @@ -1391,4 +1388,6 @@ <!-- The margin applied between complications --> <dimen name="dream_overlay_complication_margin">0dp</dimen> + + <dimen name="status_view_margin_horizontal">0dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index df16b0d45228..6d336e60e1d3 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -21,7 +21,13 @@ <string name="app_label">System UI</string> <!-- When the battery is low, this is displayed to the user in a dialog. The title of the low battery alert. [CHAR LIMIT=NONE]--> - <string name="battery_low_title">Battery may run out soon</string> + <string name="battery_low_title">Turn on Battery Saver?</string> + + <!-- When the battery is low, this is displayed to the user in a dialog. The description of the low battery alert. [CHAR LIMIT=NONE]--> + <string name="battery_low_description">You have <xliff:g id="percentage" example="20%">%s</xliff:g> battery left. Battery Saver turns on Dark theme, restricts background activity, and delays notifications.</string> + + <!-- When the battery is low at first time, this is displayed to the user in a dialog. The description of the low battery alert. [CHAR LIMIT=NONE]--> + <string name="battery_low_intro">Battery Saver turns on Dark theme, restricts background activity, and delays notifications.</string> <!-- A message that appears when the battery level is getting low in a dialog. This is appended to the subtitle of the low battery alert. "percentage" is the percentage of battery @@ -441,8 +447,8 @@ <string name="accessibility_quick_settings_dnd_none_on">total silence</string> <!-- Content description of the do not disturb tile in quick settings when on in alarms only (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_quick_settings_dnd_alarms_on">alarms only</string> - <!-- Content description of the priority mode tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] --> - <string name="accessibility_quick_settings_dnd" translatable="false">Priority mode.</string> + <!-- Content description of the do not disturb tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_quick_settings_dnd">Do Not Disturb.</string> <!-- Content description of the bluetooth tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_quick_settings_bluetooth">Bluetooth.</string> <!-- Content description of the bluetooth tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] --> @@ -520,8 +526,8 @@ <string name="ethernet_label">Ethernet</string> <!-- QuickSettings: Onboarding text that introduces users to long press on an option in order to view the option's menu in Settings [CHAR LIMIT=NONE] --> - <!-- QuickSettings: Priority mode [CHAR LIMIT=NONE] --> - <string name="quick_settings_dnd_label" translatable="false">Priority mode</string> + <!-- QuickSettings: Do not disturb [CHAR LIMIT=NONE] --> + <string name="quick_settings_dnd_label">Do Not Disturb</string> <!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] --> <!-- QuickSettings: Do not disturb - Alarms only [CHAR LIMIT=NONE] --> <!-- QuickSettings: Do not disturb - Total silence [CHAR LIMIT=NONE] --> @@ -909,8 +915,8 @@ <!-- Content description for accessibility: Tapping this button will dismiss all gentle notifications [CHAR LIMIT=NONE] --> <string name="accessibility_notification_section_header_gentle_clear_all">Clear all silent notifications</string> - <!-- The text to show in the notifications shade when Priority mode is suppressing notifications. [CHAR LIMIT=100] --> - <string name="dnd_suppressing_shade_text" translatable="false">Notifications paused by Priority mode</string> + <!-- The text to show in the notifications shade when dnd is suppressing notifications. [CHAR LIMIT=100] --> + <string name="dnd_suppressing_shade_text">Notifications paused by Do Not Disturb</string> <!-- Media projection permission dialog action text. [CHAR LIMIT=60] --> <string name="media_projection_action_text">Start now</string> @@ -1329,8 +1335,8 @@ <!-- [CHAR LIMIT=150] Notification Importance title: important conversation level summary --> <string name="notification_channel_summary_priority_baseline">Shows at the top of conversation notifications and as a profile picture on lock screen</string> <string name="notification_channel_summary_priority_bubble">Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble</string> - <string name="notification_channel_summary_priority_dnd" translatable="false">Shows at the top of conversation notifications and as a profile picture on lock screen, interrupts Priority mode</string> - <string name="notification_channel_summary_priority_all" translatable="false">Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Priority mode</string> + <string name="notification_channel_summary_priority_dnd">Shows at the top of conversation notifications and as a profile picture on lock screen, interrupts Do Not Disturb</string> + <string name="notification_channel_summary_priority_all">Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb</string> <!-- [CHAR LIMIT=150] Notification Importance title: important conversation level --> <string name="notification_priority_title">Priority</string> @@ -1521,8 +1527,8 @@ <!-- User visible title for the keyboard shortcut that takes the user to the calendar app. --> <string name="keyboard_shortcut_group_applications_calendar">Calendar</string> - <!-- SysUI Tuner: Label for screen about priority mode settings [CHAR LIMIT=60] --> - <string name="volume_and_do_not_disturb" translatable="false">Priority mode</string> + <!-- SysUI Tuner: Label for screen about do not disturb settings [CHAR LIMIT=60] --> + <string name="volume_and_do_not_disturb">Do Not Disturb</string> <!-- SysUI Tuner: Switch to control whether volume buttons enter/exit do not disturb [CHAR LIMIT=60] --> @@ -1878,17 +1884,17 @@ <!-- Label for when bluetooth is off in QS detail panel [CHAR LIMIT=NONE] --> <string name="bt_is_off">Bluetooth is off</string> - <!-- Label for when Priority mode is off in QS detail panel [CHAR LIMIT=NONE] --> - <string name="dnd_is_off" translatable="false">Priority mode is off</string> + <!-- Label for when Do not disturb is off in QS detail panel [CHAR LIMIT=NONE] --> + <string name="dnd_is_off">Do Not Disturb is off</string> - <!-- Prompt for when Priority mode is on from automatic rule in QS [CHAR LIMIT=NONE] --> - <string name="qs_dnd_prompt_auto_rule" translatable="false">Priority mode was turned on by an automatic rule (<xliff:g name="rule">%s</xliff:g>).</string> + <!-- Prompt for when Do not disturb is on from automatic rule in QS [CHAR LIMIT=NONE] --> + <string name="qs_dnd_prompt_auto_rule">Do Not Disturb was turned on by an automatic rule (<xliff:g name="rule">%s</xliff:g>).</string> - <!-- Prompt for when Priority mode is on from app in QS [CHAR LIMIT=NONE] --> - <string name="qs_dnd_prompt_app" translatable="false">Priority mode was turned on by an app (<xliff:g name="app">%s</xliff:g>).</string> + <!-- Prompt for when Do not disturb is on from app in QS [CHAR LIMIT=NONE] --> + <string name="qs_dnd_prompt_app">Do Not Disturb was turned on by an app (<xliff:g name="app">%s</xliff:g>).</string> - <!-- Prompt for when Priority mode is on from automatic rule or app in QS [CHAR LIMIT=NONE] --> - <string name="qs_dnd_prompt_auto_rule_app" translatable="false">Priority mode was turned on by an automatic rule or app.</string> + <!-- Prompt for when Do not disturb is on from automatic rule or app in QS [CHAR LIMIT=NONE] --> + <string name="qs_dnd_prompt_auto_rule_app">Do Not Disturb was turned on by an automatic rule or app.</string> <!-- Title of the "running foreground services" dialog. [CHAR LIMIT=NONE] --> <string name="running_foreground_services_title">Apps running in background</string> @@ -2284,8 +2290,8 @@ <string name="people_tile_description">See recent messages, missed calls, and status updates</string> <!-- Title text displayed for the Conversation widget [CHAR LIMIT=50] --> <string name="people_tile_title">Conversation</string> - <!-- Text when the Conversation widget when Priority mode is suppressing the notification. [CHAR LIMIT=50] --> - <string name="paused_by_dnd" translatable="false">Paused by Priority mode</string> + <!-- Text when the Conversation widget when Do Not Disturb is suppressing the notification. [CHAR LIMIT=50] --> + <string name="paused_by_dnd">Paused by Do Not Disturb</string> <!-- Content description text on the Conversation widget when a person has sent a new text message [CHAR LIMIT=150] --> <string name="new_notification_text_content_description"><xliff:g id="name" example="Anna">%1$s</xliff:g> sent a message: <xliff:g id="notification" example="Hey! How is your day going">%2$s</xliff:g></string> <!-- Content description text on the Conversation widget when a person has sent a new image message [CHAR LIMIT=150] --> @@ -2421,6 +2427,9 @@ <string name="dream_overlay_status_bar_assistant_guest_mode_enabled">Assistant guest mode enabled</string> <!-- Content description for the camera and mic off icon in the dream overlay status bar [CHAR LIMIT=NONE] --> <string name="dream_overlay_status_bar_camera_mic_off">Camera and mic are off</string> - <!-- Content description for the camera and mic off icon in the dream overlay status bar [CHAR LIMIT=NONE] --> - <string name="dream_overlay_status_bar_notification_indicator">There are notifications</string> + <!-- Content description for the notifications indicator icon in the dream overlay status bar [CHAR LIMIT=NONE] --> + <string name="dream_overlay_status_bar_notification_indicator">{count, plural, + =1 {# notification} + other {# notifications} + }</string> </resources> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java index bf23a49df2c3..ba0a6d149707 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java @@ -17,7 +17,6 @@ package com.android.systemui.shared.system; import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.WindowManager.INPUT_CONSUMER_PIP; import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION; import android.os.Binder; @@ -137,14 +136,6 @@ public class InputConsumerController { * Registers the input consumer. */ public void registerInputConsumer() { - registerInputConsumer(false); - } - - /** - * Registers the input consumer. - * @param withSfVsync the flag set using sf vsync signal or no - */ - public void registerInputConsumer(boolean withSfVsync) { if (mInputEventReceiver == null) { final InputChannel inputChannel = new InputChannel(); try { @@ -154,7 +145,7 @@ public class InputConsumerController { Log.e(TAG, "Failed to create input consumer", e); } mInputEventReceiver = new InputEventReceiver(inputChannel, Looper.myLooper(), - withSfVsync ? Choreographer.getSfInstance() : Choreographer.getInstance()); + Choreographer.getInstance()); if (mRegistrationListener != null) { mRegistrationListener.onRegistrationChanged(true /* isRegistered */); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index a72a050ee023..31f466f0fdf9 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -16,8 +16,6 @@ package com.android.keyguard; -import android.app.ActivityManager; -import android.app.IActivityManager; import android.content.Context; import android.graphics.Color; import android.util.AttributeSet; @@ -27,7 +25,6 @@ import android.widget.GridLayout; import androidx.core.graphics.ColorUtils; -import com.android.internal.widget.LockPatternUtils; import com.android.systemui.R; import com.android.systemui.statusbar.CrossFadeHelper; @@ -44,9 +41,6 @@ public class KeyguardStatusView extends GridLayout { private static final boolean DEBUG = KeyguardConstants.DEBUG; private static final String TAG = "KeyguardStatusView"; - private final LockPatternUtils mLockPatternUtils; - private final IActivityManager mIActivityManager; - private ViewGroup mStatusViewContainer; private KeyguardClockSwitch mClockView; private KeyguardSliceView mKeyguardSlice; @@ -56,14 +50,6 @@ public class KeyguardStatusView extends GridLayout { private int mTextColor; private float mChildrenAlphaExcludingSmartSpace = 1f; - /** - * Bottom margin that defines the margin between bottom of smart space and top of notification - * icons on AOD. - */ - private int mIconTopMargin; - private int mIconTopMarginWithHeader; - private boolean mShowingHeader; - public KeyguardStatusView(Context context) { this(context, null, 0); } @@ -74,8 +60,6 @@ public class KeyguardStatusView extends GridLayout { public KeyguardStatusView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mIActivityManager = ActivityManager.getService(); - mLockPatternUtils = new LockPatternUtils(getContext()); } @Override @@ -91,25 +75,11 @@ public class KeyguardStatusView extends GridLayout { mKeyguardSlice = findViewById(R.id.keyguard_slice_view); mTextColor = mClockView.getCurrentTextColor(); - mKeyguardSlice.setContentChangeListener(this::onSliceContentChanged); - onSliceContentChanged(); - mMediaHostContainer = findViewById(R.id.status_view_media_container); updateDark(); } - /** - * Moves clock, adjusting margins when slice content changes. - */ - private void onSliceContentChanged() { - final boolean hasHeader = mKeyguardSlice.hasHeader(); - if (mShowingHeader == hasHeader) { - return; - } - mShowingHeader = hasHeader; - } - void setDarkAmount(float darkAmount) { if (mDarkAmount == darkAmount) { return; @@ -158,10 +128,4 @@ public class KeyguardStatusView extends GridLayout { mKeyguardSlice.dump(fd, pw, args); } } - - private void loadBottomMargin() { - mIconTopMargin = getResources().getDimensionPixelSize(R.dimen.widget_vertical_padding); - mIconTopMarginWithHeader = getResources().getDimensionPixelSize( - R.dimen.widget_vertical_padding_with_header); - } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java index 122f3d7f23f1..295d77d55b56 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java @@ -24,9 +24,9 @@ import androidx.annotation.Nullable; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.statusbar.phone.BiometricUnlockController; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationPanelViewController; -import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; /** @@ -176,9 +176,9 @@ public interface KeyguardViewController { // achieving complete abstraction away from where the Keyguard View is mounted. /** - * Registers the StatusBar to which this Keyguard View is mounted. + * Registers the CentralSurfaces to which this Keyguard View is mounted. */ - void registerStatusBar(StatusBar statusBar, + void registerCentralSurfaces(CentralSurfaces centralSurfaces, NotificationPanelViewController notificationPanelViewController, @Nullable PanelExpansionStateManager panelExpansionStateManager, BiometricUnlockController biometricUnlockController, diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 4ad51835687f..370686a1e682 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -60,7 +60,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.VibratorHelper; -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.ViewController; @@ -78,7 +78,7 @@ import javax.inject.Inject; * For devices with UDFPS, the lock icon will show at the sensor location. Else, the lock * icon will show a set distance from the bottom of the device. */ -@StatusBarComponent.StatusBarScope +@CentralSurfacesComponent.CentralSurfacesScope public class LockIconViewController extends ViewController<LockIconView> implements Dumpable { private static final String TAG = "LockIconViewController"; private static final float sDefaultDensity = diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java index 207ac2852f2f..8dbe5e00ab7e 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java @@ -24,7 +24,7 @@ import java.lang.annotation.Retention; import javax.inject.Scope; /** - * Scope annotation for singleton items within the StatusBarComponent. + * Scope annotation for singleton items within the CentralSurfacesComponent. */ @Documented @Retention(RUNTIME) diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java index ba0642f57a88..f498ef3466ef 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java @@ -24,7 +24,7 @@ import java.lang.annotation.Retention; import javax.inject.Scope; /** - * Scope annotation for singleton items within the StatusBarComponent. + * Scope annotation for singleton items within the CentralSurfacesComponent. */ @Documented @Retention(RUNTIME) diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java index 880822aa7343..aeae8e3d4b27 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java @@ -24,7 +24,7 @@ import java.lang.annotation.Retention; import javax.inject.Scope; /** - * Scope annotation for singleton items within the StatusBarComponent. + * Scope annotation for singleton items within the CentralSurfacesComponent. */ @Documented @Retention(RUNTIME) diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java index cc166c210078..5bd620e873b0 100644 --- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java @@ -23,7 +23,7 @@ import androidx.annotation.Nullable; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.plugins.ActivityStarter; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import java.util.Optional; @@ -33,17 +33,17 @@ import dagger.Lazy; /** * Single common instance of ActivityStarter that can be gotten and referenced from anywhere, but - * delegates to an actual implementation (StatusBar). + * delegates to an actual implementation (CentralSurfaces). */ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @SysUISingleton public class ActivityStarterDelegate implements ActivityStarter { - private Lazy<Optional<StatusBar>> mActualStarterOptionalLazy; + private Lazy<Optional<CentralSurfaces>> mActualStarterOptionalLazy; @Inject - public ActivityStarterDelegate(Lazy<Optional<StatusBar>> statusBarOptionalLazy) { - mActualStarterOptionalLazy = statusBarOptionalLazy; + public ActivityStarterDelegate(Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy) { + mActualStarterOptionalLazy = centralSurfacesOptionalLazy; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java index 881e6a917a45..bd8e44ceab80 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java @@ -54,7 +54,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.recents.Recents; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationShadeWindowController; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarWindowCallback; import com.android.systemui.util.Assert; @@ -180,7 +180,7 @@ public class SystemActions extends CoreStartable { private final Optional<Recents> mRecentsOptional; private Locale mLocale; private final AccessibilityManager mA11yManager; - private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; + private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; private final NotificationShadeWindowController mNotificationShadeController; private final StatusBarWindowCallback mNotificationShadeCallback; private boolean mDismissNotificationShadeActionRegistered; @@ -188,7 +188,7 @@ public class SystemActions extends CoreStartable { @Inject public SystemActions(Context context, NotificationShadeWindowController notificationShadeController, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, Optional<Recents> recentsOptional) { super(context); mRecentsOptional = recentsOptional; @@ -201,7 +201,7 @@ public class SystemActions extends CoreStartable { // NotificationShadeWindowController.registerCallback() only keeps weak references. mNotificationShadeCallback = (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing) -> registerOrUnregisterDismissNotificationShadeAction(); - mStatusBarOptionalLazy = statusBarOptionalLazy; + mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; } @Override @@ -311,9 +311,10 @@ public class SystemActions extends CoreStartable { // Saving state in instance variable since this callback is called quite often to avoid // binder calls - final Optional<StatusBar> statusBarOptional = mStatusBarOptionalLazy.get(); - if (statusBarOptional.map(StatusBar::isPanelExpanded).orElse(false) - && !statusBarOptional.get().isKeyguardShowing()) { + final Optional<CentralSurfaces> centralSurfacesOptional = + mCentralSurfacesOptionalLazy.get(); + if (centralSurfacesOptional.map(CentralSurfaces::isPanelExpanded).orElse(false) + && !centralSurfacesOptional.get().isKeyguardShowing()) { if (!mDismissNotificationShadeActionRegistered) { mA11yManager.registerSystemAction( createRemoteAction( @@ -466,12 +467,12 @@ public class SystemActions extends CoreStartable { } private void handleNotifications() { - mStatusBarOptionalLazy.get().ifPresent(StatusBar::animateExpandNotificationsPanel); + mCentralSurfacesOptionalLazy.get().ifPresent(CentralSurfaces::animateExpandNotificationsPanel); } private void handleQuickSettings() { - mStatusBarOptionalLazy.get().ifPresent( - statusBar -> statusBar.animateExpandSettingsPanel(null)); + mCentralSurfacesOptionalLazy.get().ifPresent( + centralSurfaces -> centralSurfaces.animateExpandSettingsPanel(null)); } private void handlePowerDialog() { @@ -524,8 +525,8 @@ public class SystemActions extends CoreStartable { } private void handleAccessibilityDismissNotificationShade() { - mStatusBarOptionalLazy.get().ifPresent( - statusBar -> statusBar.animateCollapsePanels( + mCentralSurfacesOptionalLazy.get().ifPresent( + centralSurfaces -> centralSurfaces.animateCollapsePanels( CommandQueue.FLAG_EXCLUDE_NONE, false /* force */)); } diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java index aedaf968ac7d..dfff00b90ef2 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java @@ -36,7 +36,7 @@ import com.android.systemui.shared.system.PackageManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListeners; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import java.util.ArrayList; import java.util.List; @@ -69,7 +69,7 @@ public final class PhoneStateMonitor { }; private final Context mContext; - private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; + private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; private final StatusBarStateController mStatusBarStateController; private boolean mLauncherShowing; @@ -77,10 +77,11 @@ public final class PhoneStateMonitor { @Inject PhoneStateMonitor(Context context, BroadcastDispatcher broadcastDispatcher, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, BootCompleteCache bootCompleteCache, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, + BootCompleteCache bootCompleteCache, StatusBarStateController statusBarStateController) { mContext = context; - mStatusBarOptionalLazy = statusBarOptionalLazy; + mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mStatusBarStateController = statusBarStateController; mDefaultHome = getCurrentDefaultHome(); @@ -180,7 +181,8 @@ public final class PhoneStateMonitor { } private boolean isBouncerShowing() { - return mStatusBarOptionalLazy.get().map(StatusBar::isBouncerShowing).orElse(false); + return mCentralSurfacesOptionalLazy.get() + .map(CentralSurfaces::isBouncerShowing).orElse(false); } private boolean isKeyguardLocked() { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt index f82ea790bb64..99f27d7f48e7 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt @@ -40,8 +40,8 @@ import com.android.systemui.statusbar.commandline.Command import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.KeyguardBypassController -import com.android.systemui.statusbar.phone.StatusBar -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope +import com.android.systemui.statusbar.phone.CentralSurfaces +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.ViewController @@ -54,9 +54,9 @@ import javax.inject.Provider * Controls the ripple effect that shows when authentication is successful. * The ripple uses the accent color of the current theme. */ -@StatusBarScope +@CentralSurfacesScope class AuthRippleController @Inject constructor( - private val statusBar: StatusBar, + private val centralSurfaces: CentralSurfaces, private val sysuiContext: Context, private val authController: AuthController, private val configurationController: ConfigurationController, @@ -137,7 +137,7 @@ class AuthRippleController @Inject constructor( private fun showUnlockedRipple() { notificationShadeWindowController.setForcePluginOpen(true, this) - val lightRevealScrim = statusBar.lightRevealScrim + val lightRevealScrim = centralSurfaces.lightRevealScrim if (statusBarStateController.isDozing || biometricUnlockController.isWakeAndUnlock) { circleReveal?.let { lightRevealScrim?.revealEffect = it @@ -155,7 +155,7 @@ class AuthRippleController @Inject constructor( override fun onKeyguardFadingAwayChanged() { if (keyguardStateController.isKeyguardFadingAway) { - val lightRevealScrim = statusBar.lightRevealScrim + val lightRevealScrim = centralSurfaces.lightRevealScrim if (startLightRevealScrimOnKeyguardFadingAway && lightRevealScrim != null) { ValueAnimator.ofFloat(.1f, 1f).apply { interpolator = Interpolators.LINEAR_OUT_SLOW_IN @@ -170,7 +170,7 @@ class AuthRippleController @Inject constructor( } addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator?) { - // Reset light reveal scrim to the default, so the StatusBar + // Reset light reveal scrim to the default, so the CentralSurfaces // can handle any subsequent light reveal changes // (ie: from dozing changes) if (lightRevealScrim.revealEffect == circleReveal) { @@ -199,8 +199,8 @@ class AuthRippleController @Inject constructor( it.y, 0f, Math.max( - Math.max(it.x, statusBar.displayWidth - it.x), - Math.max(it.y, statusBar.displayHeight - it.y) + Math.max(it.x, centralSurfaces.displayWidth - it.x), + Math.max(it.y, centralSurfaces.displayHeight - it.y) ) ) } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java index 7204a15233b0..7efdd1a8b949 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java @@ -38,7 +38,6 @@ import androidx.asynclayoutinflater.view.AsyncLayoutInflater; import com.android.settingslib.Utils; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; -import com.android.systemui.statusbar.StatusBarState; import com.airbnb.lottie.LottieAnimationView; import com.airbnb.lottie.LottieProperty; @@ -68,6 +67,7 @@ public class UdfpsKeyguardView extends UdfpsAnimationView { private float mBurnInOffsetY; private float mBurnInProgress; private float mInterpolatedDarkAmount; + private boolean mAnimatingBetweenAodAndLockscreen; // As opposed to Unlocked => AOD private boolean mFullyInflated; public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) { @@ -114,23 +114,32 @@ public class UdfpsKeyguardView extends UdfpsAnimationView { return; } + final float darkAmountForAnimation = mAnimatingBetweenAodAndLockscreen + ? mInterpolatedDarkAmount : 1f /* animating from unlocked to AOD */; mBurnInOffsetX = MathUtils.lerp(0f, getBurnInOffset(mMaxBurnInOffsetX * 2, true /* xAxis */) - - mMaxBurnInOffsetX, mInterpolatedDarkAmount); + - mMaxBurnInOffsetX, darkAmountForAnimation); mBurnInOffsetY = MathUtils.lerp(0f, getBurnInOffset(mMaxBurnInOffsetY * 2, false /* xAxis */) - - mMaxBurnInOffsetY, mInterpolatedDarkAmount); - mBurnInProgress = MathUtils.lerp(0f, getBurnInProgressOffset(), mInterpolatedDarkAmount); + - mMaxBurnInOffsetY, darkAmountForAnimation); + mBurnInProgress = MathUtils.lerp(0f, getBurnInProgressOffset(), darkAmountForAnimation); + + if (mAnimatingBetweenAodAndLockscreen) { + mBgProtection.setAlpha(1f - mInterpolatedDarkAmount); + + mLockScreenFp.setTranslationX(mBurnInOffsetX); + mLockScreenFp.setTranslationY(mBurnInOffsetY); + mLockScreenFp.setProgress(1f - mInterpolatedDarkAmount); + mLockScreenFp.setAlpha(1f - mInterpolatedDarkAmount); + } else { + mBgProtection.setAlpha(0f); + mLockScreenFp.setAlpha(0f); + } mAodFp.setTranslationX(mBurnInOffsetX); mAodFp.setTranslationY(mBurnInOffsetY); mAodFp.setProgress(mBurnInProgress); - mAodFp.setAlpha(255 * mInterpolatedDarkAmount); - - mLockScreenFp.setTranslationX(mBurnInOffsetX); - mLockScreenFp.setTranslationY(mBurnInOffsetY); - mLockScreenFp.setProgress(1f - mInterpolatedDarkAmount); - mLockScreenFp.setAlpha((1f - mInterpolatedDarkAmount) * 255); + mAodFp.setAlpha(mInterpolatedDarkAmount); } void requestUdfps(boolean request, int color) { @@ -171,15 +180,14 @@ public class UdfpsKeyguardView extends UdfpsAnimationView { protected int updateAlpha() { int alpha = super.updateAlpha(); if (mFullyInflated) { - mLockScreenFp.setAlpha(alpha / 255f); - if (mInterpolatedDarkAmount != 0f) { - mBgProtection.setAlpha(1f - mInterpolatedDarkAmount); - } else { + if (mInterpolatedDarkAmount == 0f) { + mLockScreenFp.setAlpha(alpha / 255f); mBgProtection.setAlpha(alpha / 255f); + } else { + updateBurnInOffsets(); } } - return alpha; } @@ -191,8 +199,10 @@ public class UdfpsKeyguardView extends UdfpsAnimationView { return mAlpha; } - void onDozeAmountChanged(float linear, float eased) { + void onDozeAmountChanged(float linear, float eased, boolean animatingBetweenAodAndLockscreen) { + mAnimatingBetweenAodAndLockscreen = animatingBetweenAodAndLockscreen; mInterpolatedDarkAmount = eased; + updateAlpha(); updateBurnInOffsets(); } @@ -225,10 +235,6 @@ public class UdfpsKeyguardView extends UdfpsAnimationView { mBackgroundInAnimator.start(); } - private boolean isShadeLocked() { - return mStatusBarState == StatusBarState.SHADE_LOCKED; - } - private final AsyncLayoutInflater.OnInflateFinishedListener mLayoutInflaterFinishListener = new AsyncLayoutInflater.OnInflateFinishedListener() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java index 24a655c2856d..5ac21ff42f4f 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java @@ -18,6 +18,7 @@ package com.android.systemui.biometrics; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; +import android.animation.ValueAnimator; import android.annotation.NonNull; import android.content.res.Configuration; import android.util.Log; @@ -31,6 +32,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.KeyguardBouncer; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.SystemUIDialogManager; @@ -59,6 +61,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud @NonNull private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; @NonNull private final ActivityLaunchAnimator mActivityLaunchAnimator; + private final ValueAnimator mUnlockedScreenOffDozeAnimator = ValueAnimator.ofFloat(0f, 1f); private boolean mShowingUdfpsBouncer; private boolean mUdfpsRequested; @@ -107,6 +110,18 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud mUdfpsController = udfpsController; mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; mActivityLaunchAnimator = activityLaunchAnimator; + + mUnlockedScreenOffDozeAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); + mUnlockedScreenOffDozeAnimator.addUpdateListener( + new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mView.onDozeAmountChanged( + animation.getAnimatedFraction(), + (float) animation.getAnimatedValue(), + /* animatingBetweenAodAndLockScreen */ false); + } + }); } @Override @@ -143,7 +158,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(this); - mUnlockedScreenOffAnimationController.addCallback(mUnlockedScreenOffCallback); mActivityLaunchAnimator.addListener(mActivityLaunchAnimatorListener); } @@ -161,7 +175,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) { mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null); } - mUnlockedScreenOffAnimationController.removeCallback(mUnlockedScreenOffCallback); mActivityLaunchAnimator.removeListener(mActivityLaunchAnimatorListener); } @@ -179,6 +192,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud pw.println("mUdfpsRequested=" + mUdfpsRequested); pw.println("mView.mUdfpsRequested=" + mView.mUdfpsRequested); pw.println("mLaunchTransitionFadingAway=" + mLaunchTransitionFadingAway); + pw.println("mLastDozeAmount=" + mLastDozeAmount); } /** @@ -239,7 +253,11 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud return true; } - if (mStatusBarState != KEYGUARD) { + // Only pause auth if we're not on the keyguard AND we're not transitioning to doze + // (ie: dozeAmount = 0f). For the UnlockedScreenOffAnimation, the statusBarState is + // delayed. However, we still animate in the UDFPS affordance with the + // mUnlockedScreenOffDozeAnimator. + if (mStatusBarState != KEYGUARD && mLastDozeAmount == 0f) { return true; } @@ -299,6 +317,10 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud updateAlpha(); } + /** + * Update alpha for the UDFPS lock screen affordance. The AoD UDFPS visual affordance's + * alpha is based on the doze amount. + */ private void updateAlpha() { // fade icon on transitions to showing the status bar, but if mUdfpsRequested, then // the keyguard is occluded by some application - so instead use the input bouncer @@ -327,7 +349,18 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud if (mLastDozeAmount < linear) { showUdfpsBouncer(false); } - mView.onDozeAmountChanged(linear, eased); + mUnlockedScreenOffDozeAnimator.cancel(); + final boolean animatingFromUnlockedScreenOff = + mUnlockedScreenOffAnimationController.isAnimationPlaying(); + if (animatingFromUnlockedScreenOff && linear != 0f) { + // we manually animate the fade in of the UDFPS icon since the unlocked + // screen off animation prevents the doze amounts to be incrementally eased in + mUnlockedScreenOffDozeAnimator.start(); + } else { + mView.onDozeAmountChanged(linear, eased, + /* animatingBetweenAodAndLockScreen */ true); + } + mLastDozeAmount = linear; updatePauseAuth(); } @@ -446,9 +479,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud } }; - private final UnlockedScreenOffAnimationController.Callback mUnlockedScreenOffCallback = - (linear, eased) -> mStateListener.onDozeAmountChanged(linear, eased); - private final ActivityLaunchAnimator.Listener mActivityLaunchAnimatorListener = new ActivityLaunchAnimator.Listener() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt index f87fa96dea65..5c1d8c3929cb 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt @@ -23,7 +23,11 @@ import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.content.pm.ResolveInfo +import android.database.ContentObserver +import android.net.Uri +import android.os.Handler import android.os.VibrationEffect +import android.provider.Settings import android.service.controls.Control import android.service.controls.actions.BooleanAction import android.service.controls.actions.CommandAction @@ -38,6 +42,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.settings.SecureSettings import com.android.wm.shell.TaskViewFactory import java.util.Optional import javax.inject.Inject @@ -51,19 +56,41 @@ class ControlActionCoordinatorImpl @Inject constructor( private val keyguardStateController: KeyguardStateController, private val taskViewFactory: Optional<TaskViewFactory>, private val controlsMetricsLogger: ControlsMetricsLogger, - private val vibrator: VibratorHelper + private val vibrator: VibratorHelper, + private val secureSettings: SecureSettings, + @Main mainHandler: Handler ) : ControlActionCoordinator { private var dialog: Dialog? = null private var pendingAction: Action? = null private var actionsInProgress = mutableSetOf<String>() private val isLocked: Boolean get() = !keyguardStateController.isUnlocked() + private var mAllowTrivialControls: Boolean = secureSettings.getInt( + Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, 0) != 0 override lateinit var activityContext: Context companion object { private const val RESPONSE_TIMEOUT_IN_MILLIS = 3000L } + init { + val lockScreenShowControlsUri = + secureSettings.getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS) + val controlsContentObserver = object : ContentObserver(mainHandler) { + override fun onChange(selfChange: Boolean, uri: Uri?) { + super.onChange(selfChange, uri) + if (uri == lockScreenShowControlsUri) { + mAllowTrivialControls = secureSettings.getInt( + Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, 0) != 0 + } + } + } + secureSettings.registerContentObserver( + lockScreenShowControlsUri, + false /* notifyForDescendants */, controlsContentObserver + ) + } + override fun closeDialogs() { dialog?.dismiss() dialog = null @@ -80,7 +107,7 @@ class ControlActionCoordinatorImpl @Inject constructor( }, true /* blockable */ ), - isAuthRequired(cvh) + isAuthRequired(cvh, mAllowTrivialControls) ) } @@ -100,7 +127,7 @@ class ControlActionCoordinatorImpl @Inject constructor( }, blockable ), - isAuthRequired(cvh) + isAuthRequired(cvh, mAllowTrivialControls) ) } @@ -120,7 +147,7 @@ class ControlActionCoordinatorImpl @Inject constructor( { cvh.action(FloatAction(templateId, newValue)) }, false /* blockable */ ), - isAuthRequired(cvh) + isAuthRequired(cvh, mAllowTrivialControls) ) } @@ -139,7 +166,7 @@ class ControlActionCoordinatorImpl @Inject constructor( }, false /* blockable */ ), - isAuthRequired(cvh) + isAuthRequired(cvh, mAllowTrivialControls) ) } @@ -156,7 +183,11 @@ class ControlActionCoordinatorImpl @Inject constructor( actionsInProgress.remove(controlId) } - private fun isAuthRequired(cvh: ControlViewHolder) = cvh.cws.control?.isAuthRequired() ?: true + @VisibleForTesting() + fun isAuthRequired(cvh: ControlViewHolder, allowTrivialControls: Boolean): Boolean { + val isAuthRequired = cvh.cws.control?.isAuthRequired ?: true + return isAuthRequired || !allowTrivialControls + } private fun shouldRunAction(controlId: String) = if (actionsInProgress.add(controlId)) { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java index b32f8786899a..2f041acb649d 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java @@ -18,7 +18,7 @@ package com.android.systemui.dagger; import com.android.systemui.keyguard.dagger.KeyguardModule; import com.android.systemui.recents.RecentsModule; -import com.android.systemui.statusbar.dagger.StatusBarModule; +import com.android.systemui.statusbar.dagger.CentralSurfacesModule; import dagger.Module; @@ -27,7 +27,7 @@ import dagger.Module; */ @Module(includes = { RecentsModule.class, - StatusBarModule.class, + CentralSurfacesModule.class, KeyguardModule.class, }) public abstract class SystemUIBinder { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java index a4da6b422bde..5d154c3b4f6b 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java @@ -48,7 +48,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; import com.android.systemui.statusbar.NotificationShadeWindowController; -import com.android.systemui.statusbar.dagger.StartStatusBarModule; +import com.android.systemui.statusbar.dagger.StartCentralSurfacesModule; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; @@ -87,7 +87,7 @@ import dagger.Provides; MediaModule.class, PowerModule.class, QSModule.class, - StartStatusBarModule.class, + StartCentralSurfacesModule.class, VolumeModule.class }) public abstract class SystemUIDefaultModule { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 13067bf71165..27993010c917 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -67,8 +67,8 @@ import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotifica import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent; import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; +import com.android.systemui.statusbar.phone.CentralSurfaces; +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.ZenModeController; @@ -131,7 +131,7 @@ import dagger.Provides; WalletModule.class }, subcomponents = { - StatusBarComponent.class, + CentralSurfacesComponent.class, NotificationRowComponent.class, DozeComponent.class, ExpandableNotificationRowComponent.class, @@ -175,7 +175,7 @@ public abstract class SystemUIModule { abstract Recents optionalRecents(); @BindsOptionalOf - abstract StatusBar optionalStatusBar(); + abstract CentralSurfaces optionalCentralSurfaces(); @BindsOptionalOf abstract UdfpsHbmProvider optionalUdfpsHbmProvider(); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java index 2beed4c6a7e7..d89c0be26351 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java @@ -31,7 +31,6 @@ public interface DozeHost { boolean isPowerSaveActive(); boolean isPulsingBlocked(); boolean isProvisioned(); - boolean isBlockingDoze(); /** * Makes a current pulse last for twice as long. @@ -80,8 +79,9 @@ public interface DozeHost { */ void stopPulsing(); - /** Returns whether doze is suppressed. */ - boolean isDozeSuppressed(); + /** Returns whether always-on-display is suppressed. This does not include suppressing + * wake-up gestures. */ + boolean isAlwaysOnSuppressed(); interface Callback { /** @@ -97,8 +97,10 @@ public interface DozeHost { */ default void onPowerSaveChanged(boolean active) {} - /** Called when the doze suppression state changes. */ - default void onDozeSuppressedChanged(boolean suppressed) {} + /** + * Called when the always on suppression state changes. See {@link #isAlwaysOnSuppressed()}. + */ + default void onAlwaysOnSuppressedChanged(boolean suppressed) {} } interface PulseCallback { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index 25115200ba19..0a2e69f943c6 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -132,14 +132,6 @@ public class DozeLog implements Dumpable { } /** - * Appends dozing event to the logs - * @param suppressed true if dozing is suppressed - */ - public void traceDozingSuppressed(boolean suppressed) { - mLogger.logDozingSuppressed(suppressed); - } - - /** * Appends fling event to the logs */ public void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded, @@ -325,15 +317,40 @@ public class DozeLog implements Dumpable { } /** - * Appends doze suppressed event to the logs + * Appends the doze state that was suppressed to the doze event log * @param suppressedState The {@link DozeMachine.State} that was suppressed */ - public void traceDozeSuppressed(DozeMachine.State suppressedState) { - mLogger.logDozeSuppressed(suppressedState); + public void traceAlwaysOnSuppressed(DozeMachine.State suppressedState) { + mLogger.logAlwaysOnSuppressed(suppressedState); + } + + /** + * Appends reason why doze immediately ended. + */ + public void traceImmediatelyEndDoze(String reason) { + mLogger.logImmediatelyEndDoze(reason); + } + + /** + * Appends power save changes that may cause a new doze state + * @param powerSaveActive true if power saving is active + * @param nextState the state that we'll transition to + */ + public void tracePowerSaveChanged(boolean powerSaveActive, DozeMachine.State nextState) { + mLogger.logPowerSaveChanged(powerSaveActive, nextState); + } + + /** + * Appends an event on AOD suppression change + * @param suppressed true if AOD is being suppressed + * @param nextState the state that we'll transition to + */ + public void traceAlwaysOnSuppressedChange(boolean suppressed, DozeMachine.State nextState) { + mLogger.logAlwaysOnSuppressedChange(suppressed, nextState); } /** - * Appends new AOD sreen brightness to logs + * Appends new AOD screen brightness to logs * @param brightness display brightness setting */ public void traceDozeScreenBrightness(int brightness) { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt index 4ba6b51c83c8..f3f6be210fed 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt @@ -74,11 +74,21 @@ class DozeLogger @Inject constructor( }) } - fun logDozingSuppressed(isDozingSuppressed: Boolean) { + fun logPowerSaveChanged(powerSaveActive: Boolean, nextState: DozeMachine.State) { buffer.log(TAG, INFO, { - bool1 = isDozingSuppressed + bool1 = powerSaveActive + str1 = nextState.name }, { - "DozingSuppressed=$bool1" + "Power save active=$bool1 nextState=$str1" + }) + } + + fun logAlwaysOnSuppressedChange(isAodSuppressed: Boolean, nextState: DozeMachine.State) { + buffer.log(TAG, INFO, { + bool1 = isAodSuppressed + str1 = nextState.name + }, { + "Always on (AOD) suppressed changed, suppressed=$bool1 nextState=$str1" }) } @@ -257,11 +267,19 @@ class DozeLogger @Inject constructor( }) } - fun logDozeSuppressed(state: DozeMachine.State) { + fun logAlwaysOnSuppressed(state: DozeMachine.State) { buffer.log(TAG, INFO, { str1 = state.name }, { - "Doze state suppressed, state=$str1" + "Always-on state suppressed, suppressed state=$str1" + }) + } + + fun logImmediatelyEndDoze(reason: String) { + buffer.log(TAG, INFO, { + str1 = reason + }, { + "Doze immediately ended due to $str1" }) } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index 789ad6223e79..ae01f0ad84c7 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -357,9 +357,9 @@ public class DozeMachine { if (mState == State.FINISH) { return State.FINISH; } - if (mDozeHost.isDozeSuppressed() && requestedState.isAlwaysOn()) { + if (mDozeHost.isAlwaysOnSuppressed() && requestedState.isAlwaysOn()) { Log.i(TAG, "Doze is suppressed. Suppressing state: " + requestedState); - mDozeLog.traceDozeSuppressed(requestedState); + mDozeLog.traceAlwaysOnSuppressed(requestedState); return State.DOZE; } if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD_PAUSING @@ -415,7 +415,6 @@ public class DozeMachine { pw.print(" state="); pw.println(mState); pw.print(" wakeLockHeldForCurrentState="); pw.println(mWakeLockHeldForCurrentState); pw.print(" wakeLock="); pw.println(mWakeLock); - pw.print(" isDozeSuppressed="); pw.println(mDozeHost.isDozeSuppressed()); pw.println("Parts:"); for (Part p : mParts) { p.dump(pw); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java new file mode 100644 index 000000000000..31d43b5475e0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java @@ -0,0 +1,195 @@ +/* + * 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.doze; + +import static android.app.UiModeManager.ACTION_ENTER_CAR_MODE; + +import android.app.UiModeManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Configuration; +import android.hardware.display.AmbientDisplayConfiguration; +import android.os.PowerManager; +import android.os.UserHandle; +import android.text.TextUtils; + +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.doze.dagger.DozeScope; +import com.android.systemui.statusbar.phone.BiometricUnlockController; + +import java.io.PrintWriter; + +import javax.inject.Inject; + +import dagger.Lazy; + +/** + * Handles suppressing doze on: + * 1. INITIALIZED, don't allow dozing at all when: + * - in CAR_MODE + * - device is NOT provisioned + * - there's a pending authentication + * 2. PowerSaveMode active + * - no always-on-display (DOZE_AOD) + * - continues to allow doze triggers (DOZE, DOZE_REQUEST_PULSE) + * 3. Suppression changes from the PowerManager API. See {@link PowerManager#suppressAmbientDisplay} + * and {@link DozeHost#isAlwaysOnSuppressed()}. + * - no always-on-display (DOZE_AOD) + * - allow doze triggers (DOZE), but disallow notifications (handled by {@link DozeTriggers}) + * - See extra check in {@link DozeMachine} to guarantee device never enters always-on states + */ +@DozeScope +public class DozeSuppressor implements DozeMachine.Part { + private static final String TAG = "DozeSuppressor"; + + private DozeMachine mMachine; + private final DozeHost mDozeHost; + private final AmbientDisplayConfiguration mConfig; + private final DozeLog mDozeLog; + private final BroadcastDispatcher mBroadcastDispatcher; + private final UiModeManager mUiModeManager; + private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; + + private boolean mBroadcastReceiverRegistered; + + @Inject + public DozeSuppressor( + DozeHost dozeHost, + AmbientDisplayConfiguration config, + DozeLog dozeLog, + BroadcastDispatcher broadcastDispatcher, + UiModeManager uiModeManager, + Lazy<BiometricUnlockController> biometricUnlockControllerLazy) { + mDozeHost = dozeHost; + mConfig = config; + mDozeLog = dozeLog; + mBroadcastDispatcher = broadcastDispatcher; + mUiModeManager = uiModeManager; + mBiometricUnlockControllerLazy = biometricUnlockControllerLazy; + } + + @Override + public void setDozeMachine(DozeMachine dozeMachine) { + mMachine = dozeMachine; + } + + @Override + public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) { + switch (newState) { + case INITIALIZED: + registerBroadcastReceiver(); + mDozeHost.addCallback(mHostCallback); + checkShouldImmediatelyEndDoze(); + break; + case FINISH: + destroy(); + break; + default: + } + } + + @Override + public void destroy() { + unregisterBroadcastReceiver(); + mDozeHost.removeCallback(mHostCallback); + } + + private void checkShouldImmediatelyEndDoze() { + String reason = null; + if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR) { + reason = "car_mode"; + } else if (!mDozeHost.isProvisioned()) { + reason = "device_unprovisioned"; + } else if (mBiometricUnlockControllerLazy.get().hasPendingAuthentication()) { + reason = "has_pending_auth"; + } + + if (!TextUtils.isEmpty(reason)) { + mDozeLog.traceImmediatelyEndDoze(reason); + mMachine.requestState(DozeMachine.State.FINISH); + } + } + + @Override + public void dump(PrintWriter pw) { + pw.println(" uiMode=" + mUiModeManager.getCurrentModeType()); + pw.println(" hasPendingAuth=" + + mBiometricUnlockControllerLazy.get().hasPendingAuthentication()); + pw.println(" isProvisioned=" + mDozeHost.isProvisioned()); + pw.println(" isAlwaysOnSuppressed=" + mDozeHost.isAlwaysOnSuppressed()); + pw.println(" aodPowerSaveActive=" + mDozeHost.isPowerSaveActive()); + } + + private void registerBroadcastReceiver() { + if (mBroadcastReceiverRegistered) { + return; + } + IntentFilter filter = new IntentFilter(ACTION_ENTER_CAR_MODE); + mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter); + mBroadcastReceiverRegistered = true; + } + + private void unregisterBroadcastReceiver() { + if (!mBroadcastReceiverRegistered) { + return; + } + mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver); + mBroadcastReceiverRegistered = false; + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (ACTION_ENTER_CAR_MODE.equals(intent.getAction())) { + mDozeLog.traceImmediatelyEndDoze("car_mode"); + mMachine.requestState(DozeMachine.State.FINISH); + } + } + }; + + private DozeHost.Callback mHostCallback = new DozeHost.Callback() { + @Override + public void onPowerSaveChanged(boolean active) { + DozeMachine.State nextState = null; + if (mDozeHost.isPowerSaveActive()) { + nextState = DozeMachine.State.DOZE; + } else if (mMachine.getState() == DozeMachine.State.DOZE + && mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) { + nextState = DozeMachine.State.DOZE_AOD; + } + + if (nextState != null) { + mDozeLog.tracePowerSaveChanged(mDozeHost.isPowerSaveActive(), nextState); + mMachine.requestState(nextState); + } + } + + @Override + public void onAlwaysOnSuppressedChanged(boolean suppressed) { + final DozeMachine.State nextState; + if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) && !suppressed) { + nextState = DozeMachine.State.DOZE_AOD; + } else { + nextState = DozeMachine.State.DOZE; + } + mDozeLog.traceAlwaysOnSuppressedChange(suppressed, nextState); + mMachine.requestState(nextState); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 8bff3ba0b6ba..74044e2c2eb8 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -17,12 +17,10 @@ package com.android.systemui.doze; import android.annotation.Nullable; -import android.app.UiModeManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.Configuration; import android.hardware.display.AmbientDisplayConfiguration; import android.os.SystemClock; import android.os.UserHandle; @@ -88,7 +86,6 @@ public class DozeTriggers implements DozeMachine.Part { private final AsyncSensorManager mSensorManager; private final WakeLock mWakeLock; private final boolean mAllowPulseTriggers; - private final UiModeManager mUiModeManager; private final TriggerReceiver mBroadcastReceiver = new TriggerReceiver(); private final DockEventListener mDockEventListener = new DockEventListener(); private final DockManager mDockManager; @@ -203,8 +200,6 @@ public class DozeTriggers implements DozeMachine.Part { mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters, config, wakeLock, this::onSensor, this::onProximityFar, dozeLog, proximitySensor, secureSettings, authController, devicePostureController); - - mUiModeManager = mContext.getSystemService(UiModeManager.class); mDockManager = dockManager; mProxCheck = proxCheck; mDozeLog = dozeLog; @@ -247,7 +242,7 @@ public class DozeTriggers implements DozeMachine.Part { mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled"); return; } - if (mDozeHost.isDozeSuppressed()) { + if (mDozeHost.isAlwaysOnSuppressed()) { runIfNotNull(onPulseSuppressedListener); mDozeLog.tracePulseDropped("dozeSuppressed"); return; @@ -456,10 +451,9 @@ public class DozeTriggers implements DozeMachine.Part { mAodInterruptRunnable = null; sWakeDisplaySensorState = true; mBroadcastReceiver.register(mBroadcastDispatcher); - mDozeHost.addCallback(mHostCallback); mDockManager.addListener(mDockEventListener); mDozeSensors.requestTemporaryDisable(); - checkTriggersAtInit(); + mDozeHost.addCallback(mHostCallback); break; case DOZE: case DOZE_AOD: @@ -516,15 +510,6 @@ public class DozeTriggers implements DozeMachine.Part { } } - - private void checkTriggersAtInit() { - if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR - || mDozeHost.isBlockingDoze() - || !mDozeHost.isProvisioned()) { - mMachine.requestState(DozeMachine.State.FINISH); - } - } - private void requestPulse(final int reason, boolean performedProxCheck, Runnable onPulseSuppressedListener) { Assert.isMainThread(); @@ -608,9 +593,6 @@ public class DozeTriggers implements DozeMachine.Part { requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */ null /* onPulseSuppressedListener */); } - if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) { - mMachine.requestState(DozeMachine.State.FINISH); - } if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { mDozeSensors.onUserSwitched(); } @@ -621,7 +603,6 @@ public class DozeTriggers implements DozeMachine.Part { return; } IntentFilter filter = new IntentFilter(PULSE_ACTION); - filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE); filter.addAction(Intent.ACTION_USER_SWITCHED); broadcastDispatcher.registerReceiver(this, filter); mRegistered = true; @@ -659,26 +640,5 @@ public class DozeTriggers implements DozeMachine.Part { public void onNotificationAlerted(Runnable onPulseSuppressedListener) { onNotification(onPulseSuppressedListener); } - - @Override - public void onPowerSaveChanged(boolean active) { - if (mDozeHost.isPowerSaveActive()) { - mMachine.requestState(DozeMachine.State.DOZE); - } else if (mMachine.getState() == DozeMachine.State.DOZE - && mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) { - mMachine.requestState(DozeMachine.State.DOZE_AOD); - } - } - - @Override - public void onDozeSuppressedChanged(boolean suppressed) { - final DozeMachine.State nextState; - if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) && !suppressed) { - nextState = DozeMachine.State.DOZE_AOD; - } else { - nextState = DozeMachine.State.DOZE; - } - mMachine.requestState(nextState); - } }; } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java index 2d969206b468..d2ab61149d26 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java @@ -16,23 +16,44 @@ package com.android.systemui.dreams; +import android.annotation.IntDef; +import android.annotation.Nullable; import android.content.Context; import android.util.AttributeSet; import android.view.View; -import android.widget.ImageView; import androidx.constraintlayout.widget.ConstraintLayout; -import com.android.internal.util.Preconditions; import com.android.systemui.R; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + /** * {@link DreamOverlayStatusBarView} is the view responsible for displaying the status bar in a * dream. The status bar displays conditional status icons such as "priority mode" and "no wifi". */ public class DreamOverlayStatusBarView extends ConstraintLayout { - private ImageView mWifiStatusView; + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "STATUS_ICON_" }, value = { + STATUS_ICON_NOTIFICATIONS, + STATUS_ICON_WIFI_UNAVAILABLE, + STATUS_ICON_ALARM_SET, + STATUS_ICON_MIC_CAMERA_DISABLED, + STATUS_ICON_PRIORITY_MODE_ON + }) + public @interface StatusIconType {} + public static final int STATUS_ICON_NOTIFICATIONS = 0; + public static final int STATUS_ICON_WIFI_UNAVAILABLE = 1; + public static final int STATUS_ICON_ALARM_SET = 2; + public static final int STATUS_ICON_MIC_CAMERA_DISABLED = 3; + public static final int STATUS_ICON_PRIORITY_MODE_ON = 4; + + private final Map<Integer, View> mStatusIcons = new HashMap<>(); public DreamOverlayStatusBarView(Context context) { this(context, null); @@ -55,16 +76,35 @@ public class DreamOverlayStatusBarView extends ConstraintLayout { protected void onFinishInflate() { super.onFinishInflate(); - mWifiStatusView = Preconditions.checkNotNull(findViewById(R.id.dream_overlay_wifi_status), - "R.id.dream_overlay_wifi_status must not be null"); + mStatusIcons.put(STATUS_ICON_WIFI_UNAVAILABLE, + fetchStatusIconForResId(R.id.dream_overlay_wifi_status)); + mStatusIcons.put(STATUS_ICON_ALARM_SET, + fetchStatusIconForResId(R.id.dream_overlay_alarm_set)); + mStatusIcons.put(STATUS_ICON_MIC_CAMERA_DISABLED, + fetchStatusIconForResId(R.id.dream_overlay_camera_mic_off)); + mStatusIcons.put(STATUS_ICON_NOTIFICATIONS, + fetchStatusIconForResId(R.id.dream_overlay_notification_indicator)); + mStatusIcons.put(STATUS_ICON_PRIORITY_MODE_ON, + fetchStatusIconForResId(R.id.dream_overlay_priority_mode)); + } + + void showIcon(@StatusIconType int iconType, boolean show) { + showIcon(iconType, show, null); + } + + void showIcon(@StatusIconType int iconType, boolean show, @Nullable String contentDescription) { + View icon = mStatusIcons.get(iconType); + if (icon == null) { + return; + } + if (show && contentDescription != null) { + icon.setContentDescription(contentDescription); + } + icon.setVisibility(show ? View.VISIBLE : View.GONE); } - /** - * Whether to show the wifi status icon. - * @param show True if the wifi status icon should be shown. - */ - void showWifiStatus(boolean show) { - // Only show the wifi status icon when wifi isn't available. - mWifiStatusView.setVisibility(show ? View.VISIBLE : View.GONE); + private View fetchStatusIconForResId(int resId) { + final View statusIcon = findViewById(resId); + return Objects.requireNonNull(statusIcon); } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java index 32b2309ee83b..a25a7423770e 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java @@ -16,19 +16,35 @@ package com.android.systemui.dreams; -import android.annotation.IntDef; +import android.app.AlarmManager; +import android.content.res.Resources; +import android.hardware.SensorPrivacyManager; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; - +import android.os.UserHandle; +import android.provider.Settings; +import android.service.notification.NotificationListenerService.RankingMap; +import android.service.notification.StatusBarNotification; +import android.text.format.DateFormat; +import android.util.PluralsMessageFormatter; + +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dreams.dagger.DreamOverlayComponent; +import com.android.systemui.statusbar.NotificationListener; +import com.android.systemui.statusbar.NotificationListener.NotificationHandler; +import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController; +import com.android.systemui.statusbar.policy.NextAlarmController; +import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.touch.TouchInsetManager; import com.android.systemui.util.ViewController; +import com.android.systemui.util.time.DateFormatUtil; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; +import java.util.Locale; +import java.util.Map; import javax.inject.Inject; @@ -37,19 +53,15 @@ import javax.inject.Inject; */ @DreamOverlayComponent.DreamOverlayScope public class DreamOverlayStatusBarViewController extends ViewController<DreamOverlayStatusBarView> { - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "WIFI_STATUS_" }, value = { - WIFI_STATUS_UNKNOWN, - WIFI_STATUS_UNAVAILABLE, - WIFI_STATUS_AVAILABLE - }) - private @interface WifiStatus {} - private static final int WIFI_STATUS_UNKNOWN = 0; - private static final int WIFI_STATUS_UNAVAILABLE = 1; - private static final int WIFI_STATUS_AVAILABLE = 2; - private final ConnectivityManager mConnectivityManager; private final TouchInsetManager.TouchInsetSession mTouchInsetSession; + private final NextAlarmController mNextAlarmController; + private final AlarmManager mAlarmManager; + private final Resources mResources; + private final DateFormatUtil mDateFormatUtil; + private final IndividualSensorPrivacyController mSensorPrivacyController; + private final NotificationListener mNotificationListener; + private final ZenModeController mZenModeController; private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder() .clearCapabilities() @@ -59,61 +71,183 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve @Override public void onCapabilitiesChanged( Network network, NetworkCapabilities networkCapabilities) { - onWifiAvailabilityChanged( - networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)); + updateWifiUnavailableStatusIcon(); } @Override public void onAvailable(Network network) { - onWifiAvailabilityChanged(true); + updateWifiUnavailableStatusIcon(); } @Override public void onLost(Network network) { - onWifiAvailabilityChanged(false); + updateWifiUnavailableStatusIcon(); } }; - private @WifiStatus int mWifiStatus = WIFI_STATUS_UNKNOWN; + private final IndividualSensorPrivacyController.Callback mSensorCallback = + (sensor, blocked) -> updateMicCameraBlockedStatusIcon(); + + private final NextAlarmController.NextAlarmChangeCallback mNextAlarmCallback = + nextAlarm -> updateAlarmStatusIcon(); + + private final NotificationHandler mNotificationHandler = new NotificationHandler() { + @Override + public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) { + updateNotificationsStatusIcon(); + } + + @Override + public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) { + updateNotificationsStatusIcon(); + } + + @Override + public void onNotificationRemoved( + StatusBarNotification sbn, + RankingMap rankingMap, + int reason) { + updateNotificationsStatusIcon(); + } + + @Override + public void onNotificationRankingUpdate(RankingMap rankingMap) { + } + + @Override + public void onNotificationsInitialized() { + updateNotificationsStatusIcon(); + } + }; + + private final ZenModeController.Callback mZenModeCallback = new ZenModeController.Callback() { + @Override + public void onZenChanged(int zen) { + updatePriorityModeStatusIcon(); + } + }; @Inject public DreamOverlayStatusBarViewController( DreamOverlayStatusBarView view, + @Main Resources resources, ConnectivityManager connectivityManager, - TouchInsetManager.TouchInsetSession touchInsetSession) { + TouchInsetManager.TouchInsetSession touchInsetSession, + AlarmManager alarmManager, + NextAlarmController nextAlarmController, + DateFormatUtil dateFormatUtil, + IndividualSensorPrivacyController sensorPrivacyController, + NotificationListener notificationListener, + ZenModeController zenModeController) { super(view); + mResources = resources; mConnectivityManager = connectivityManager; mTouchInsetSession = touchInsetSession; + mAlarmManager = alarmManager; + mNextAlarmController = nextAlarmController; + mDateFormatUtil = dateFormatUtil; + mSensorPrivacyController = sensorPrivacyController; + mNotificationListener = notificationListener; + mZenModeController = zenModeController; + + // Handlers can be added to NotificationListener, but apparently they can't be removed. So + // add the handler here in the constructor rather than in onViewAttached to avoid confusion. + mNotificationListener.addNotificationHandler(mNotificationHandler); } @Override protected void onViewAttached() { + updateNotificationsStatusIcon(); + mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback); + updateWifiUnavailableStatusIcon(); + + mNextAlarmController.addCallback(mNextAlarmCallback); + updateAlarmStatusIcon(); + + mSensorPrivacyController.addCallback(mSensorCallback); + updateMicCameraBlockedStatusIcon(); + + mZenModeController.addCallback(mZenModeCallback); + updatePriorityModeStatusIcon(); - NetworkCapabilities capabilities = - mConnectivityManager.getNetworkCapabilities( - mConnectivityManager.getActiveNetwork()); - onWifiAvailabilityChanged( - capabilities != null - && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)); mTouchInsetSession.addViewToTracking(mView); } @Override protected void onViewDetached() { + mZenModeController.removeCallback(mZenModeCallback); + mSensorPrivacyController.removeCallback(mSensorCallback); + mNextAlarmController.removeCallback(mNextAlarmCallback); mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); mTouchInsetSession.clear(); } - /** - * Wifi availability has changed. Update the wifi status icon as appropriate. - * @param available Whether wifi is available. - */ - private void onWifiAvailabilityChanged(boolean available) { - final int newWifiStatus = available ? WIFI_STATUS_AVAILABLE : WIFI_STATUS_UNAVAILABLE; - if (mWifiStatus != newWifiStatus) { - mWifiStatus = newWifiStatus; - mView.showWifiStatus(mWifiStatus == WIFI_STATUS_UNAVAILABLE); + private void updateWifiUnavailableStatusIcon() { + final NetworkCapabilities capabilities = + mConnectivityManager.getNetworkCapabilities( + mConnectivityManager.getActiveNetwork()); + final boolean available = capabilities != null + && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI); + mView.showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available); + } + + private void updateAlarmStatusIcon() { + final AlarmManager.AlarmClockInfo alarm = + mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT); + final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0; + mView.showIcon( + DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET, + hasAlarm, + hasAlarm ? buildAlarmContentDescription(alarm) : null); + } + + private String buildAlarmContentDescription(AlarmManager.AlarmClockInfo alarm) { + final String skeleton = mDateFormatUtil.is24HourFormat() ? "EHm" : "Ehma"; + final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton); + final String dateString = DateFormat.format(pattern, alarm.getTriggerTime()).toString(); + + return mResources.getString(R.string.accessibility_quick_settings_alarm, dateString); + } + + private void updateMicCameraBlockedStatusIcon() { + final boolean micBlocked = mSensorPrivacyController + .isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE); + final boolean cameraBlocked = mSensorPrivacyController + .isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA); + mView.showIcon( + DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, + micBlocked && cameraBlocked); + } + + private void updateNotificationsStatusIcon() { + if (mView == null) { + // It is possible for this method to be called before the view is attached, which makes + // null-checking necessary. + return; } + + final StatusBarNotification[] notifications = + mNotificationListener.getActiveNotifications(); + final int notificationCount = notifications != null ? notifications.length : 0; + mView.showIcon( + DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS, + notificationCount > 0, + notificationCount > 0 + ? buildNotificationsContentDescription(notificationCount) + : null); + } + + private String buildNotificationsContentDescription(int notificationCount) { + return PluralsMessageFormatter.format( + mResources, + Map.of("count", notificationCount), + R.string.dream_overlay_status_bar_notification_indicator); + } + + private void updatePriorityModeStatusIcon() { + mView.showIcon( + DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, + mZenModeController.getZen() != Settings.Global.ZEN_MODE_OFF); } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamPreviewComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamPreviewComplication.java index 23343b17232f..cc2e57128204 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamPreviewComplication.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamPreviewComplication.java @@ -20,6 +20,8 @@ import static com.android.systemui.dreams.complication.dagger.DreamPreviewCompli import static com.android.systemui.dreams.complication.dagger.DreamPreviewComplicationComponent.DreamPreviewComplicationModule.DREAM_PREVIEW_COMPLICATION_LAYOUT_PARAMS; import static com.android.systemui.dreams.complication.dagger.DreamPreviewComplicationComponent.DreamPreviewComplicationModule.DREAM_PREVIEW_COMPLICATION_VIEW; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.view.View; import android.widget.TextView; @@ -86,6 +88,11 @@ public class DreamPreviewComplication implements Complication { if (!TextUtils.isEmpty(dreamLabel)) { mView.setText(dreamLabel); } + for (Drawable drawable : mView.getCompoundDrawablesRelative()) { + if (drawable instanceof BitmapDrawable) { + drawable.setAutoMirrored(true); + } + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java index d16c8c8c59d6..e140f6b0faa2 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java @@ -21,6 +21,9 @@ import static com.android.systemui.dreams.touch.dagger.BouncerSwipeModule.SWIPE_ import static com.android.systemui.dreams.touch.dagger.BouncerSwipeModule.SWIPE_TO_BOUNCER_START_REGION; import android.animation.ValueAnimator; +import android.graphics.Rect; +import android.graphics.Region; +import android.util.DisplayMetrics; import android.util.Log; import android.view.GestureDetector; import android.view.InputEvent; @@ -29,7 +32,7 @@ import android.view.VelocityTracker; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.KeyguardBouncer; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.wm.shell.animation.FlingAnimationUtils; @@ -68,13 +71,15 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private float mCurrentExpansion; - private final StatusBar mStatusBar; + private final CentralSurfaces mCentralSurfaces; private VelocityTracker mVelocityTracker; private final FlingAnimationUtils mFlingAnimationUtils; private final FlingAnimationUtils mFlingAnimationUtilsClosing; + private final DisplayMetrics mDisplayMetrics; + private Boolean mCapture; private TouchSession mTouchSession; @@ -85,40 +90,9 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { private final GestureDetector.OnGestureListener mOnGestureListener = new GestureDetector.SimpleOnGestureListener() { - boolean mTrack; - boolean mBouncerPresent; - - @Override - public boolean onDown(MotionEvent e) { - // We only consider gestures that originate from the lower portion of the - // screen. - final float displayHeight = mStatusBar.getDisplayHeight(); - - mBouncerPresent = mStatusBar.isBouncerShowing(); - - // The target zone is either at the top or bottom of the screen, dependent on - // whether the bouncer is present. - final float zonePercentage = - Math.abs(e.getY() - (mBouncerPresent ? 0 : displayHeight)) - / displayHeight; - - mTrack = zonePercentage < mBouncerZoneScreenPercentage; - - // Never capture onDown. While this might lead to some false positive touches - // being sent to other windows/layers, this is necessary to make sure the - // proper touch event sequence is received by others in the event we do not - // consume the sequence here. - return false; - } - @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - // Do not handle scroll gestures if not tracking touch events. - if (!mTrack) { - return false; - } - if (mCapture == null) { // If the user scrolling favors a vertical direction, begin capturing // scrolls. @@ -140,10 +114,9 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { // is fully hidden at full expansion (1) and fully visible when fully collapsed // (0). final float screenTravelPercentage = - Math.abs((e1.getY() - e2.getY()) / mStatusBar.getDisplayHeight()); - setPanelExpansion( - mBouncerPresent ? screenTravelPercentage : 1 - screenTravelPercentage); - + Math.abs((e1.getY() - e2.getY()) / mCentralSurfaces.getDisplayHeight()); + setPanelExpansion(mCentralSurfaces.isBouncerShowing() + ? screenTravelPercentage : 1 - screenTravelPercentage); return true; } }; @@ -155,8 +128,9 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { @Inject public BouncerSwipeTouchHandler( + DisplayMetrics displayMetrics, StatusBarKeyguardViewManager statusBarKeyguardViewManager, - StatusBar statusBar, + CentralSurfaces centralSurfaces, NotificationShadeWindowController notificationShadeWindowController, ValueAnimatorCreator valueAnimatorCreator, VelocityTrackerFactory velocityTrackerFactory, @@ -165,7 +139,8 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { @Named(SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_OPENING) FlingAnimationUtils flingAnimationUtilsClosing, @Named(SWIPE_TO_BOUNCER_START_REGION) float swipeRegionPercentage) { - mStatusBar = statusBar; + mDisplayMetrics = displayMetrics; + mCentralSurfaces = centralSurfaces; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mNotificationShadeWindowController = notificationShadeWindowController; mBouncerZoneScreenPercentage = swipeRegionPercentage; @@ -176,6 +151,21 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { } @Override + public void getTouchInitiationRegion(Region region) { + if (mCentralSurfaces.isBouncerShowing()) { + region.op(new Rect(0, 0, mDisplayMetrics.widthPixels, + Math.round(mDisplayMetrics.heightPixels * mBouncerZoneScreenPercentage)), + Region.Op.UNION); + } else { + region.op(new Rect(0, + Math.round(mDisplayMetrics.heightPixels * (1 - mBouncerZoneScreenPercentage)), + mDisplayMetrics.widthPixels, + mDisplayMetrics.heightPixels), + Region.Op.UNION); + } + } + + @Override public void onSessionStart(TouchSession session) { mVelocityTracker = mVelocityTrackerFactory.obtain(); mTouchSession = session; @@ -202,7 +192,9 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { final MotionEvent motionEvent = (MotionEvent) event; switch(motionEvent.getAction()) { + case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: + mTouchSession.pop(); // If we are not capturing any input, there is no need to consider animating to // finish transition. if (mCapture == null || !mCapture) { @@ -226,7 +218,6 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { if (expansion == KeyguardBouncer.EXPANSION_HIDDEN) { mStatusBarKeyguardViewManager.reset(false); } - mTouchSession.pop(); break; default: mVelocityTracker.addMovement(motionEvent); @@ -255,7 +246,7 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { } protected void flingToExpansion(float velocity, float expansion) { - final float viewHeight = mStatusBar.getDisplayHeight(); + final float viewHeight = mCentralSurfaces.getDisplayHeight(); final float currentHeight = viewHeight * mCurrentExpansion; final float targetHeight = viewHeight * expansion; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java index 3e5efb2115a0..695b59ac45ad 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java @@ -16,6 +16,7 @@ package com.android.systemui.dreams.touch; +import android.graphics.Region; import android.view.GestureDetector; import android.view.InputEvent; import android.view.MotionEvent; @@ -34,6 +35,7 @@ import com.android.systemui.shared.system.InputChannelCompat; import com.google.common.util.concurrent.ListenableFuture; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.concurrent.Executor; @@ -100,6 +102,10 @@ public class DreamOverlayTouchMonitor { }); } + private int getSessionCount() { + return mActiveTouchSessions.size(); + } + /** * {@link TouchSessionImpl} implements {@link DreamTouchHandler.TouchSession} for * {@link DreamOverlayTouchMonitor}. It enables the monitor to access the associated listeners @@ -146,6 +152,11 @@ public class DreamOverlayTouchMonitor { return mTouchMonitor.pop(this); } + @Override + public int getActiveSessionCount() { + return mTouchMonitor.getSessionCount(); + } + /** * Returns the active listeners to receive touch events. */ @@ -229,12 +240,39 @@ public class DreamOverlayTouchMonitor { public void onInputEvent(InputEvent ev) { // No Active sessions are receiving touches. Create sessions for each listener if (mActiveTouchSessions.isEmpty()) { + final HashMap<DreamTouchHandler, DreamTouchHandler.TouchSession> sessionMap = + new HashMap<>(); + for (DreamTouchHandler handler : mHandlers) { + final Region initiationRegion = Region.obtain(); + handler.getTouchInitiationRegion(initiationRegion); + + if (!initiationRegion.isEmpty()) { + // Initiation regions require a motion event to determine pointer location + // within the region. + if (!(ev instanceof MotionEvent)) { + continue; + } + + final MotionEvent motionEvent = (MotionEvent) ev; + + // If the touch event is outside the region, then ignore. + if (!initiationRegion.contains(Math.round(motionEvent.getX()), + Math.round(motionEvent.getY()))) { + continue; + } + } + final TouchSessionImpl sessionStack = new TouchSessionImpl(DreamOverlayTouchMonitor.this, null); mActiveTouchSessions.add(sessionStack); - handler.onSessionStart(sessionStack); + sessionMap.put(handler, sessionStack); } + + // Informing handlers of new sessions is delayed until we have all created so the + // final session is correct. + sessionMap.forEach((dreamTouchHandler, touchSession) + -> dreamTouchHandler.onSessionStart(touchSession)); } // Find active sessions and invoke on InputEvent. diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java index c73ff733854d..20008d5b02c8 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java @@ -16,6 +16,7 @@ package com.android.systemui.dreams.touch; +import android.graphics.Region; import android.view.GestureDetector; import com.android.systemui.shared.system.InputChannelCompat; @@ -71,6 +72,19 @@ public interface DreamTouchHandler { * if the popped {@link TouchSession} was the initial session or has already been popped. */ ListenableFuture<TouchSession> pop(); + + /** + * Returns the number of currently active sessions. + */ + int getActiveSessionCount(); + } + + /** + * Returns the region the touch handler is interested in. By default, no region is specified, + * indicating the entire screen should be considered. + * @param region A {@link Region} that is passed in to the target entry touch region. + */ + default void getTouchInitiationRegion(Region region) { } /** diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java index e746cafb5ea0..74d5bd577cf4 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java @@ -33,7 +33,7 @@ import javax.inject.Inject; import javax.inject.Provider; /** - * Manages power menu plugins and communicates power menu actions to the StatusBar. + * Manages power menu plugins and communicates power menu actions to the CentralSurfaces. */ @SysUISingleton public class GlobalActionsComponent extends CoreStartable diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java index e3886cd80a42..7a278f786a67 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java @@ -121,7 +121,7 @@ import com.android.systemui.plugins.GlobalActionsPanelPlugin; import com.android.systemui.scrim.ScrimDrawable; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.VibratorHelper; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -236,7 +236,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms protected Handler mMainHandler; private int mSmallestScreenWidthDp; - private final Optional<StatusBar> mStatusBarOptional; + private final Optional<CentralSurfaces> mCentralSurfacesOptional; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final DialogLaunchAnimator mDialogLaunchAnimator; @@ -344,7 +344,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene RingerModeTracker ringerModeTracker, @Main Handler handler, PackageManager packageManager, - Optional<StatusBar> statusBarOptional, + Optional<CentralSurfaces> centralSurfacesOptional, KeyguardUpdateMonitor keyguardUpdateMonitor, DialogLaunchAnimator dialogLaunchAnimator) { mContext = context; @@ -374,7 +374,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene mRingerModeTracker = ringerModeTracker; mMainHandler = handler; mSmallestScreenWidthDp = resources.getConfiguration().smallestScreenWidthDp; - mStatusBarOptional = statusBarOptional; + mCentralSurfacesOptional = centralSurfacesOptional; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mDialogLaunchAnimator = dialogLaunchAnimator; @@ -426,8 +426,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene return mUiEventLogger; } - protected Optional<StatusBar> getStatusBar() { - return mStatusBarOptional; + protected Optional<CentralSurfaces> getCentralSurfaces() { + return mCentralSurfacesOptional; } protected KeyguardUpdateMonitor getKeyguardUpdateMonitor() { @@ -675,7 +675,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActionsLite, mAdapter, mOverflowAdapter, mSysuiColorExtractor, mStatusBarService, mNotificationShadeWindowController, this::onRefresh, mKeyguardShowing, - mPowerAdapter, mUiEventLogger, mStatusBarOptional, mKeyguardUpdateMonitor, + mPowerAdapter, mUiEventLogger, mCentralSurfacesOptional, mKeyguardUpdateMonitor, mLockPatternUtils); dialog.setOnDismissListener(this); @@ -866,7 +866,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene mUiEventLogger.log(GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS); if (mTelecomManager != null) { // Close shade so user sees the activity - mStatusBarOptional.ifPresent(StatusBar::collapseShade); + mCentralSurfacesOptional.ifPresent(CentralSurfaces::collapseShade); Intent intent = mTelecomManager.createLaunchEmergencyDialerIntent( null /* number */); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK @@ -998,7 +998,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene mIActivityManager.requestInteractiveBugReport(); } // Close shade so user sees the activity - mStatusBarOptional.ifPresent(StatusBar::collapseShade); + mCentralSurfacesOptional.ifPresent(CentralSurfaces::collapseShade); } catch (RemoteException e) { } } @@ -1018,7 +1018,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene mUiEventLogger.log(GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS); mIActivityManager.requestFullBugReport(); // Close shade so user sees the activity - mStatusBarOptional.ifPresent(StatusBar::collapseShade); + mCentralSurfacesOptional.ifPresent(CentralSurfaces::collapseShade); } catch (RemoteException e) { } return false; @@ -2160,7 +2160,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene protected final Runnable mOnRefreshCallback; private UiEventLogger mUiEventLogger; private GestureDetector mGestureDetector; - private Optional<StatusBar> mStatusBarOptional; + private Optional<CentralSurfaces> mCentralSurfacesOptional; private KeyguardUpdateMonitor mKeyguardUpdateMonitor; private LockPatternUtils mLockPatternUtils; private float mWindowDimAmount; @@ -2188,8 +2188,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (distanceY < 0 && distanceY > distanceX - && e1.getY() <= mStatusBarOptional.map( - StatusBar::getStatusBarHeight).orElse(0)) { + && e1.getY() <= mCentralSurfacesOptional.map( + CentralSurfaces::getStatusBarHeight).orElse(0)) { // Downwards scroll from top openShadeAndDismiss(); return true; @@ -2201,8 +2201,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if (velocityY > 0 && Math.abs(velocityY) > Math.abs(velocityX) - && e1.getY() <= mStatusBarOptional.map( - StatusBar::getStatusBarHeight).orElse(0)) { + && e1.getY() <= mCentralSurfacesOptional.map( + CentralSurfaces::getStatusBarHeight).orElse(0)) { // Downwards fling from top openShadeAndDismiss(); return true; @@ -2217,7 +2217,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene NotificationShadeWindowController notificationShadeWindowController, Runnable onRefreshCallback, boolean keyguardShowing, MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger, - Optional<StatusBar> statusBarOptional, KeyguardUpdateMonitor keyguardUpdateMonitor, + Optional<CentralSurfaces> centralSurfacesOptional, + KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils) { // We set dismissOnDeviceLock to false because we have a custom broadcast receiver to // dismiss this dialog when the device is locked. @@ -2232,7 +2233,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene mOnRefreshCallback = onRefreshCallback; mKeyguardShowing = keyguardShowing; mUiEventLogger = uiEventLogger; - mStatusBarOptional = statusBarOptional; + mCentralSurfacesOptional = centralSurfacesOptional; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; mGestureDetector = new GestureDetector(mContext, mGestureListener); @@ -2262,14 +2263,14 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene private void openShadeAndDismiss() { mUiEventLogger.log(GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE); - if (mStatusBarOptional.map(StatusBar::isKeyguardShowing).orElse(false)) { + if (mCentralSurfacesOptional.map(CentralSurfaces::isKeyguardShowing).orElse(false)) { // match existing lockscreen behavior to open QS when swiping from status bar - mStatusBarOptional.ifPresent( - statusBar -> statusBar.animateExpandSettingsPanel(null)); + mCentralSurfacesOptional.ifPresent( + centralSurfaces -> centralSurfaces.animateExpandSettingsPanel(null)); } else { // otherwise, swiping down should expand notification shade - mStatusBarOptional.ifPresent( - statusBar -> statusBar.animateExpandNotificationsPanel()); + mCentralSurfacesOptional.ifPresent( + centralSurfaces -> centralSurfaces.animateExpandNotificationsPanel()); } dismiss(); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index ae7147ecae03..c01d2c316a93 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -127,7 +127,7 @@ import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; @@ -1667,11 +1667,16 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, return; } - // if the keyguard is already showing, don't bother. check flags in both files - // to account for the hiding animation which results in a delay and discrepancy - // between flags - if (mShowing && mKeyguardViewControllerLazy.get().isShowing()) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing"); + // If the keyguard is already showing, don't bother unless it was in the process of going + // away. If it was going away, keyguard state may be out of sync and we should make sure to + // re-show it explicitly. Check flags in both files to account for the hiding animation + // which results in a delay and discrepancy between flags. + if ((mShowing && mKeyguardViewControllerLazy.get().isShowing()) + && !mKeyguardStateController.isKeyguardGoingAway()) { + if (DEBUG) { + Log.d(TAG, "doKeyguard: not showing " + + "because it is already showing and not going away"); + } resetStateLocked(); return; } @@ -2186,7 +2191,14 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, mKeyguardExitAnimationRunner = null; mScreenOnCoordinator.setWakeAndUnlocking(false); mPendingLock = false; - setShowingLocked(true); + + // If we're asked to re-show while the keyguard is going away, force callbacks to ensure + // that state is re-set correctly. Otherwise, we might short circuit since mShowing is + // true during the keyguard going away process, despite having partially set some state + // to unlocked. + setShowingLocked( + true, mKeyguardStateController.isKeyguardGoingAway() /* forceCallbacks */); + mKeyguardViewControllerLazy.get().show(options); resetKeyguardDonePendingLocked(); mHideAnimationRun = false; @@ -2356,14 +2368,28 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, @Override public void onAnimationFinished() throws RemoteException { try { + // WindowManager always needs to know that this animation + // finished so it does not wait the 10s until timeout. finishedCallback.onAnimationFinished(); } catch (RemoteException e) { Slog.w(TAG, "Failed to call onAnimationFinished", e); } - onKeyguardExitFinished(); - mKeyguardViewControllerLazy.get().hide(0 /* startTime */, - 0 /* fadeoutDuration */); - mInteractionJankMonitor.end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION); + + // If we're not interactive, it means the device is going back to + // sleep. This happens if the power button is pressed during the + // activity launch. If we're going back to sleep, we should *not* + // run keyguard exit finished callbacks and hide the keyguard, since + // we are in the process of locking again and this might result in + // the device staying unlocked when it shouldn't. + // We need to directly query isInteractive rather than mGoingToSleep + // because mGoingToSleep is set in onStartedGoingToSleep, which is + // dispatched asynchronously. + if (mPM.isInteractive()) { + onKeyguardExitFinished(); + mKeyguardViewControllerLazy.get().hide(0 /* startTime */, + 0 /* fadeoutDuration */); + mInteractionJankMonitor.end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION); + } } @Override @@ -2717,22 +2743,22 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, } /** - * Registers the StatusBar to which the Keyguard View is mounted. + * Registers the CentralSurfaces to which the Keyguard View is mounted. * - * @param statusBar + * @param centralSurfaces * @param panelView * @param biometricUnlockController * @param notificationContainer * @param bypassController * @return the View Controller for the Keyguard View this class is mediating. */ - public KeyguardViewController registerStatusBar(StatusBar statusBar, + public KeyguardViewController registerCentralSurfaces(CentralSurfaces centralSurfaces, NotificationPanelViewController panelView, @Nullable PanelExpansionStateManager panelExpansionStateManager, BiometricUnlockController biometricUnlockController, View notificationContainer, KeyguardBypassController bypassController) { - mKeyguardViewControllerLazy.get().registerStatusBar( - statusBar, + mKeyguardViewControllerLazy.get().registerCentralSurfaces( + centralSurfaces, panelView, panelExpansionStateManager, biometricUnlockController, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index 195ef1a84c43..c69f947f5f3f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -48,10 +48,10 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardLiftController; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; -import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.DeviceConfigProxy; @@ -64,7 +64,7 @@ import dagger.Module; import dagger.Provides; /** - * Dagger Module providing {@link StatusBar}. + * Dagger Module providing keyguard. */ @Module(subcomponents = { KeyguardQsUserSwitchComponent.class, diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 7b850504421d..fab06c288ce1 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -550,12 +550,12 @@ class MediaDataManager( // Album art val notif: Notification = sbn.notification - var artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ART) + var artworkBitmap = metadata?.let { loadBitmapFromUri(it) } if (artworkBitmap == null) { - artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART) + artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ART) } - if (artworkBitmap == null && metadata != null) { - artworkBitmap = loadBitmapFromUri(metadata) + if (artworkBitmap == null) { + artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART) } val artWorkIcon = if (artworkBitmap == null) { notif.getLargeIcon() diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt index eee39552bcc8..c6f716ca7ac4 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt @@ -785,7 +785,11 @@ class MediaHierarchyManager @Inject constructor( * @return true if this transformation is guided by an external progress like a finger */ private fun isCurrentlyInGuidedTransformation(): Boolean { - return getTransformationProgress() >= 0 + return hasValidStartAndEndLocations() && getTransformationProgress() >= 0 + } + + private fun hasValidStartAndEndLocations(): Boolean { + return previousLocation != -1 && desiredLocation != -1 } /** @@ -795,6 +799,9 @@ class MediaHierarchyManager @Inject constructor( @TransformationType fun calculateTransformationType(): Int { if (isTransitioningToFullShade) { + if (inSplitShade) { + return TRANSFORMATION_TYPE_TRANSITION + } return TRANSFORMATION_TYPE_FADE } if (previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QS || @@ -961,6 +968,7 @@ class MediaHierarchyManager @Inject constructor( (qsExpansion > 0.0f || inSplitShade) && !onLockscreen -> LOCATION_QS qsExpansion > 0.4f && onLockscreen -> LOCATION_QS !hasActiveMedia -> LOCATION_QS + onLockscreen && isSplitShadeExpanding() -> LOCATION_QS onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS onLockscreen && allowedOnLockscreen -> LOCATION_LOCKSCREEN else -> LOCATION_QQS @@ -986,6 +994,10 @@ class MediaHierarchyManager @Inject constructor( return location } + private fun isSplitShadeExpanding(): Boolean { + return inSplitShade && isTransitioningToFullShade + } + /** * Are we currently transforming to the full shade and already in QQS */ @@ -993,6 +1005,10 @@ class MediaHierarchyManager @Inject constructor( if (!isTransitioningToFullShade) { return false } + if (inSplitShade) { + // Split shade doesn't use QQS. + return false + } return fullShadeTransitionProgress > 0.5f } @@ -1000,6 +1016,10 @@ class MediaHierarchyManager @Inject constructor( * Is the current transformationType fading */ private fun isCurrentlyFading(): Boolean { + if (isSplitShadeExpanding()) { + // Split shade always uses transition instead of fade. + return false + } if (isTransitioningToFullShade) { return true } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java index e2716e992c48..77873e829be3 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java @@ -38,12 +38,10 @@ import android.text.TextPaint; import android.text.TextUtils; import android.text.style.StyleSpan; import android.util.Log; -import android.view.View; import android.view.Window; -import android.view.WindowManager; -import android.widget.TextView; import com.android.systemui.R; +import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.util.Utils; public class MediaProjectionPermissionActivity extends Activity @@ -56,7 +54,7 @@ public class MediaProjectionPermissionActivity extends Activity private int mUid; private IMediaProjectionManager mService; - private AlertDialog mDialog; + private SystemUIDialog mDialog; @Override public void onCreate(Bundle icicle) { @@ -143,25 +141,18 @@ public class MediaProjectionPermissionActivity extends Activity dialogTitle = getString(R.string.media_projection_dialog_title, appName); } - View dialogTitleView = View.inflate(this, R.layout.media_projection_dialog_title, null); - TextView titleText = (TextView) dialogTitleView.findViewById(R.id.dialog_title); - titleText.setText(dialogTitle); - - mDialog = new AlertDialog.Builder(this) - .setCustomTitle(dialogTitleView) - .setMessage(dialogText) - .setPositiveButton(R.string.media_projection_action_text, this) - .setNegativeButton(android.R.string.cancel, this) - .setOnCancelListener(this) - .create(); + mDialog = new SystemUIDialog(this); + mDialog.setTitle(dialogTitle); + mDialog.setIcon(R.drawable.ic_media_projection_permission); + mDialog.setMessage(dialogText); + mDialog.setPositiveButton(R.string.media_projection_action_text, this); + mDialog.setNeutralButton(android.R.string.cancel, this); + mDialog.setOnCancelListener(this); mDialog.create(); mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true); final Window w = mDialog.getWindow(); - // QS is not closed when pressing CastTile. Match the type of the dialog shown from the - // tile. - w.setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); w.addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); mDialog.show(); diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt index 6ec2b6e89cb0..15b8f13ee0f8 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt @@ -22,6 +22,7 @@ import android.content.Context import android.graphics.PixelFormat import android.view.Gravity import android.view.LayoutInflater +import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.view.WindowManager @@ -31,6 +32,7 @@ import com.android.systemui.R import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.statusbar.gesture.TapGestureDetector import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.view.ViewUtil /** * A superclass controller that provides common functionality for showing chips on the sender device @@ -42,6 +44,7 @@ import com.android.systemui.util.concurrency.DelayableExecutor abstract class MediaTttChipControllerCommon<T : MediaTttChipState>( internal val context: Context, private val windowManager: WindowManager, + private val viewUtil: ViewUtil, @Main private val mainExecutor: DelayableExecutor, private val tapGestureDetector: TapGestureDetector, @LayoutRes private val chipLayoutRes: Int @@ -84,7 +87,7 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>( // Add view if necessary if (oldChipView == null) { - tapGestureDetector.addOnGestureDetectedCallback(TAG, this::removeChip) + tapGestureDetector.addOnGestureDetectedCallback(TAG, this::onScreenTapped) windowManager.addView(chipView, windowLayoutParams) } @@ -127,6 +130,15 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>( appIconView.setImageDrawable(appIcon) appIconView.visibility = visibility } + + private fun onScreenTapped(e: MotionEvent) { + val view = chipView ?: return + // If the tap is within the chip bounds, we shouldn't hide the chip (in case users think the + // chip is tappable). + if (!viewUtil.touchIsWithinView(view, e.x, e.y)) { + removeChip() + } + } } // Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt index b6f1aea9a384..3d43ebe81742 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt @@ -31,6 +31,7 @@ import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCom import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.gesture.TapGestureDetector import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.view.ViewUtil import javax.inject.Inject /** @@ -43,11 +44,17 @@ class MediaTttChipControllerReceiver @Inject constructor( commandQueue: CommandQueue, context: Context, windowManager: WindowManager, + viewUtil: ViewUtil, mainExecutor: DelayableExecutor, tapGestureDetector: TapGestureDetector, @Main private val mainHandler: Handler, ) : MediaTttChipControllerCommon<ChipStateReceiver>( - context, windowManager, mainExecutor, tapGestureDetector, R.layout.media_ttt_chip_receiver + context, + windowManager, + viewUtil, + mainExecutor, + tapGestureDetector, + R.layout.media_ttt_chip_receiver ) { private val commandQueueCallbacks = object : CommandQueue.Callbacks { override fun updateMediaTapToTransferReceiverDisplay( diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt index fef17fdcbbdc..180e4ee9726c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt @@ -32,6 +32,7 @@ import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCom import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.gesture.TapGestureDetector import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.view.ViewUtil import javax.inject.Inject /** @@ -43,10 +44,11 @@ class MediaTttChipControllerSender @Inject constructor( commandQueue: CommandQueue, context: Context, windowManager: WindowManager, + viewUtil: ViewUtil, @Main mainExecutor: DelayableExecutor, tapGestureDetector: TapGestureDetector, ) : MediaTttChipControllerCommon<ChipStateSender>( - context, windowManager, mainExecutor, tapGestureDetector, R.layout.media_ttt_chip + context, windowManager, viewUtil, mainExecutor, tapGestureDetector, R.layout.media_ttt_chip ) { private val commandQueueCallbacks = object : CommandQueue.Callbacks { override fun updateMediaTapToTransferSenderDisplay( diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java index 5e9edb7c906e..a1a319814269 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java @@ -49,8 +49,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.system.QuickStepContract; -import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; +import com.android.systemui.statusbar.phone.CentralSurfaces; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -79,7 +78,7 @@ public final class NavBarHelper implements Dumpable { private final AccessibilityManager mAccessibilityManager; private final Lazy<AssistManager> mAssistManagerLazy; - private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; + private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; private final UserTracker mUserTracker; private final SystemActions mSystemActions; private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver; @@ -113,7 +112,7 @@ public final class NavBarHelper implements SystemActions systemActions, OverviewProxyService overviewProxyService, Lazy<AssistManager> assistManagerLazy, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, NavigationModeController navigationModeController, UserTracker userTracker, DumpManager dumpManager) { @@ -121,7 +120,7 @@ public final class NavBarHelper implements mContentResolver = mContext.getContentResolver(); mAccessibilityManager = accessibilityManager; mAssistManagerLazy = assistManagerLazy; - mStatusBarOptionalLazy = statusBarOptionalLazy; + mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mUserTracker = userTracker; mSystemActions = systemActions; accessibilityManager.addAccessibilityServicesStateChangeListener( @@ -295,8 +294,8 @@ public final class NavBarHelper implements * {@link InputMethodService} and the keyguard states. */ public boolean isImeShown(int vis) { - View shadeWindowView = mStatusBarOptionalLazy.get().get().getNotificationShadeWindowView(); - boolean isKeyguardShowing = mStatusBarOptionalLazy.get().get().isKeyguardShowing(); + View shadeWindowView = mCentralSurfacesOptionalLazy.get().get().getNotificationShadeWindowView(); + boolean isKeyguardShowing = mCentralSurfacesOptionalLazy.get().get().isKeyguardShowing(); boolean imeVisibleOnShade = shadeWindowView != null && shadeWindowView.isAttachedToWindow() && shadeWindowView.getRootWindowInsets().isVisible(WindowInsets.Type.ime()); return imeVisibleOnShade diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java index 76914f3fd8ee..3ab1216777e9 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java @@ -53,8 +53,8 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode; -import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE; -import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions; +import static com.android.systemui.statusbar.phone.CentralSurfaces.DEBUG_WINDOW_STATE; +import static com.android.systemui.statusbar.phone.CentralSurfaces.dumpBarTransitions; import android.annotation.IdRes; import android.app.ActivityTaskManager; @@ -134,9 +134,9 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.BarTransitions; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.pip.Pip; @@ -176,7 +176,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, private final MetricsLogger mMetricsLogger; private final Lazy<AssistManager> mAssistManagerLazy; private final SysUiState mSysUiFlagsContainer; - private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; + private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; private final ShadeController mShadeController; private final NotificationRemoteInputManager mNotificationRemoteInputManager; private final OverviewProxyService mOverviewProxyService; @@ -486,7 +486,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, CommandQueue commandQueue, Optional<Pip> pipOptional, Optional<Recents> recentsOptional, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, ShadeController shadeController, NotificationRemoteInputManager notificationRemoteInputManager, NotificationShadeDepthController notificationShadeDepthController, @@ -509,7 +509,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, mMetricsLogger = metricsLogger; mAssistManagerLazy = assistManagerLazy; mSysUiFlagsContainer = sysUiFlagsContainer; - mStatusBarOptionalLazy = statusBarOptionalLazy; + mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mShadeController = shadeController; mNotificationRemoteInputManager = notificationRemoteInputManager; mOverviewProxyService = overviewProxyService; @@ -611,7 +611,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, public void onViewAttachedToWindow(View v) { final Display display = v.getDisplay(); mNavigationBarView.setComponents(mRecentsOptional); - mNavigationBarView.setComponents(mStatusBarOptionalLazy.get().get().getPanelController()); + mNavigationBarView.setComponents(mCentralSurfacesOptionalLazy.get().get().getPanelController()); mNavigationBarView.setDisabledFlags(mDisabledFlags1); mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged); mNavigationBarView.setOnTouchListener(this::onNavigationTouch); @@ -1165,13 +1165,14 @@ public class NavigationBar implements View.OnAttachStateChangeListener, // If an incoming call is ringing, HOME is totally disabled. // (The user is already on the InCallUI at this point, // and their ONLY options are to answer or reject the call.) - final Optional<StatusBar> statusBarOptional = mStatusBarOptionalLazy.get(); + final Optional<CentralSurfaces> centralSurfacesOptional = mCentralSurfacesOptionalLazy.get(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mHomeBlockedThisTouch = false; if (mTelecomManagerOptional.isPresent() && mTelecomManagerOptional.get().isRinging()) { - if (statusBarOptional.map(StatusBar::isKeyguardShowing).orElse(false)) { + if (centralSurfacesOptional.map(CentralSurfaces::isKeyguardShowing) + .orElse(false)) { Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " + "No heads up"); mHomeBlockedThisTouch = true; @@ -1187,14 +1188,14 @@ public class NavigationBar implements View.OnAttachStateChangeListener, case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mHandler.removeCallbacks(mOnVariableDurationHomeLongClick); - statusBarOptional.ifPresent(StatusBar::awakenDreams); + centralSurfacesOptional.ifPresent(CentralSurfaces::awakenDreams); break; } return false; } private void onVerticalChanged(boolean isVertical) { - mStatusBarOptionalLazy.get().ifPresent( + mCentralSurfacesOptionalLazy.get().ifPresent( statusBar -> statusBar.setQsScrimEnabled(!isVertical)); } @@ -1221,7 +1222,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, AssistManager.INVOCATION_TYPE_KEY, AssistManager.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS); mAssistManagerLazy.get().startAssist(args); - mStatusBarOptionalLazy.get().ifPresent(StatusBar::awakenDreams); + mCentralSurfacesOptionalLazy.get().ifPresent(CentralSurfaces::awakenDreams); mNavigationBarView.abortCurrentGesture(); return true; } @@ -1247,7 +1248,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, LatencyTracker.getInstance(mContext).onActionStart( LatencyTracker.ACTION_TOGGLE_RECENTS); } - mStatusBarOptionalLazy.get().ifPresent(StatusBar::awakenDreams); + mCentralSurfacesOptionalLazy.get().ifPresent(CentralSurfaces::awakenDreams); mCommandQueue.toggleRecentApps(); } @@ -1431,7 +1432,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, private void checkBarModes() { // We only have status bar on default display now. if (mIsOnDefaultDisplay) { - mStatusBarOptionalLazy.get().ifPresent(StatusBar::checkBarModes); + mCentralSurfacesOptionalLazy.get().ifPresent(CentralSurfaces::checkBarModes); } else { checkNavBarModes(); } @@ -1450,7 +1451,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener, */ public void checkNavBarModes() { final boolean anim = - mStatusBarOptionalLazy.get().map(StatusBar::isDeviceInteractive).orElse(false) + mCentralSurfacesOptionalLazy.get().map(CentralSurfaces::isDeviceInteractive) + .orElse(false) && mNavigationBarWindowState != WINDOW_STATE_HIDDEN; mNavigationBarView.getBarTransitions().transitionTo(mNavigationBarMode, anim); } @@ -1626,7 +1628,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, private final CommandQueue mCommandQueue; private final Optional<Pip> mPipOptional; private final Optional<Recents> mRecentsOptional; - private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; + private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; private final ShadeController mShadeController; private final NotificationRemoteInputManager mNotificationRemoteInputManager; private final NotificationShadeDepthController mNotificationShadeDepthController; @@ -1657,7 +1659,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, CommandQueue commandQueue, Optional<Pip> pipOptional, Optional<Recents> recentsOptional, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, ShadeController shadeController, NotificationRemoteInputManager notificationRemoteInputManager, NotificationShadeDepthController notificationShadeDepthController, @@ -1685,7 +1687,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, mCommandQueue = commandQueue; mPipOptional = pipOptional; mRecentsOptional = recentsOptional; - mStatusBarOptionalLazy = statusBarOptionalLazy; + mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mShadeController = shadeController; mNotificationRemoteInputManager = notificationRemoteInputManager; mNotificationShadeDepthController = notificationShadeDepthController; @@ -1710,7 +1712,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, mOverviewProxyService, mNavigationModeController, mAccessibilityButtonModeObserver, mStatusBarStateController, mSysUiFlagsContainer, mBroadcastDispatcher, mCommandQueue, mPipOptional, - mRecentsOptional, mStatusBarOptionalLazy, + mRecentsOptional, mCentralSurfacesOptionalLazy, mShadeController, mNotificationRemoteInputManager, mNotificationShadeDepthController, mMainHandler, mNavbarOverlayController, mUiEventLogger, mNavBarHelper, diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java index ede10a5f2f18..017bbdffdc4f 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java @@ -90,7 +90,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.LightBarTransitionsController; import com.android.systemui.statusbar.phone.NotificationPanelViewController; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.pip.Pip; @@ -1362,7 +1362,7 @@ public class NavigationBarView extends FrameLayout implements getContextDisplay().getRealSize(size); pw.println("NavigationBarView:"); - pw.println(String.format(" this: " + StatusBar.viewInfo(this) + pw.println(String.format(" this: " + CentralSurfaces.viewInfo(this) + " " + visibilityToString(getVisibility()))); getWindowVisibleDisplayFrame(r); diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java index dbd641bffe7e..039c33315741 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java @@ -118,6 +118,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private static final String ACTION_AUTO_SAVER_NO_THANKS = "PNW.autoSaverNoThanks"; + private static final String ACTION_ENABLE_SEVERE_BATTERY_DIALOG = "PNW.enableSevereDialog"; + private static final String SETTINGS_ACTION_OPEN_BATTERY_SAVER_SETTING = "android.settings.BATTERY_SAVER_SETTINGS"; public static final String BATTERY_SAVER_SCHEDULE_SCREEN_INTENT_ACTION = @@ -253,20 +255,25 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } protected void showWarningNotification() { - final String percentage = NumberFormat.getPercentInstance() - .format((double) mCurrentBatterySnapshot.getBatteryLevel() / 100.0); - - // get shared standard notification copy - String title = mContext.getString(R.string.battery_low_title); - String contentText; - - // get correct content text if notification is hybrid or not - if (mCurrentBatterySnapshot.isHybrid()) { - contentText = getHybridContentString(percentage); - } else { - contentText = mContext.getString(R.string.battery_low_percent_format, percentage); + if (showSevereLowBatteryDialog()) { + mContext.sendBroadcast(new Intent(ACTION_ENABLE_SEVERE_BATTERY_DIALOG) + .setPackage(mContext.getPackageName()) + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY + | Intent.FLAG_RECEIVER_FOREGROUND)); + // Reset the state once dialog been enabled + dismissLowBatteryNotification(); + mPlaySound = false; + return; } + final int warningLevel = mContext.getResources().getInteger( + com.android.internal.R.integer.config_lowBatteryWarningLevel); + final String percentage = NumberFormat.getPercentInstance() + .format((double) warningLevel / 100.0); + final String title = mContext.getString(R.string.battery_low_title); + final String contentText = mContext.getString( + R.string.battery_low_description, percentage); + final Notification.Builder nb = new Notification.Builder(mContext, NotificationChannels.BATTERY) .setSmallIcon(R.drawable.ic_power_low) @@ -284,7 +291,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } // Make the notification red if the percentage goes below a certain amount or the time // remaining estimate is disabled - if (!mCurrentBatterySnapshot.isHybrid() || mBucket < 0 + if (!mCurrentBatterySnapshot.isHybrid() || mBucket < -1 || mCurrentBatterySnapshot.getTimeRemainingMillis() < mCurrentBatterySnapshot.getSevereThresholdMillis()) { nb.setColor(Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorError)); @@ -303,6 +310,13 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { mNoMan.notifyAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, n, UserHandle.ALL); } + private boolean showSevereLowBatteryDialog() { + final boolean isSevereState = !mCurrentBatterySnapshot.isHybrid() || mBucket < -1; + final boolean useSevereDialog = mContext.getResources().getBoolean( + R.bool.config_severe_battery_dialog); + return isSevereState && useSevereDialog; + } + private void showAutoSaverSuggestionNotification() { final CharSequence message = mContext.getString(R.string.auto_saver_text); final Notification.Builder nb = @@ -662,8 +676,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { // If there's no link, use the string with no "learn more". if (TextUtils.isEmpty(learnMoreUrl)) { - return mContext.getText( - com.android.internal.R.string.battery_saver_description); + return mContext.getText(R.string.battery_low_intro); } // If we have a link, use the string with the "learn more" link. diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index 642af593c211..56528c9974ac 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -47,7 +47,7 @@ import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -69,7 +69,7 @@ public class PowerUI extends CoreStartable implements CommandQueue.Callbacks { private static final long TEMPERATURE_LOGGING_INTERVAL = DateUtils.HOUR_IN_MILLIS; private static final int MAX_RECENT_TEMPS = 125; // TEMPERATURE_LOGGING_INTERVAL plus a buffer static final long THREE_HOURS_IN_MILLIS = DateUtils.HOUR_IN_MILLIS * 3; - private static final int CHARGE_CYCLE_PERCENT_RESET = 45; + private static final int CHARGE_CYCLE_PERCENT_RESET = 30; private static final long SIX_HOURS_MILLIS = Duration.ofHours(6).toMillis(); public static final int NO_ESTIMATE_AVAILABLE = -1; private static final String BOOT_COUNT_KEY = "boot_count"; @@ -108,17 +108,17 @@ public class PowerUI extends CoreStartable implements CommandQueue.Callbacks { private IThermalEventListener mUsbThermalEventListener; private final BroadcastDispatcher mBroadcastDispatcher; private final CommandQueue mCommandQueue; - private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; + private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; @Inject public PowerUI(Context context, BroadcastDispatcher broadcastDispatcher, - CommandQueue commandQueue, Lazy<Optional<StatusBar>> statusBarOptionalLazy, + CommandQueue commandQueue, Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, WarningsUI warningsUI, EnhancedEstimates enhancedEstimates, PowerManager powerManager) { super(context); mBroadcastDispatcher = broadcastDispatcher; mCommandQueue = commandQueue; - mStatusBarOptionalLazy = statusBarOptionalLazy; + mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mWarnings = warningsUI; mEnhancedEstimates = enhancedEstimates; mPowerManager = powerManager; @@ -206,7 +206,8 @@ public class PowerUI extends CoreStartable implements CommandQueue.Callbacks { * * 1 means that the battery is "ok" * 0 means that the battery is between "ok" and what we should warn about. - * less than 0 means that the battery is low + * less than 0 means that the battery is low, -1 means the battery is reaching warning level, + * -2 means the battery is reaching severe level. */ private int findBatteryLevelBucket(int level) { if (level >= mLowBatteryAlertCloseLevel) { @@ -388,12 +389,8 @@ public class PowerUI extends CoreStartable implements CommandQueue.Callbacks { @VisibleForTesting void maybeShowHybridWarning(BatteryStateSnapshot currentSnapshot, BatteryStateSnapshot lastSnapshot) { - // if we are now over 45% battery & 6 hours remaining so we can trigger hybrid - // notification again - final long timeRemainingMillis = currentSnapshot.getTimeRemainingMillis(); - if (currentSnapshot.getBatteryLevel() >= CHARGE_CYCLE_PERCENT_RESET - && (timeRemainingMillis > SIX_HOURS_MILLIS - || timeRemainingMillis == NO_ESTIMATE_AVAILABLE)) { + // if we are now over 30% battery, we can trigger hybrid notification again + if (currentSnapshot.getBatteryLevel() >= CHARGE_CYCLE_PERCENT_RESET) { mLowWarningShownThisChargeCycle = false; mSevereWarningShownThisChargeCycle = false; if (DEBUG) { @@ -403,6 +400,7 @@ public class PowerUI extends CoreStartable implements CommandQueue.Callbacks { final boolean playSound = currentSnapshot.getBucket() != lastSnapshot.getBucket() || lastSnapshot.getPlugged(); + final long timeRemainingMillis = currentSnapshot.getTimeRemainingMillis(); if (shouldShowHybridWarning(currentSnapshot)) { mWarnings.showLowBatteryWarning(playSound); @@ -444,19 +442,13 @@ public class PowerUI extends CoreStartable implements CommandQueue.Callbacks { return false; } - final long timeRemainingMillis = snapshot.getTimeRemainingMillis(); // Only show the low warning if enabled once per charge cycle & no battery saver - final boolean canShowWarning = snapshot.isLowWarningEnabled() - && !mLowWarningShownThisChargeCycle && !snapshot.isPowerSaver() - && ((timeRemainingMillis != NO_ESTIMATE_AVAILABLE - && timeRemainingMillis < snapshot.getLowThresholdMillis()) - || snapshot.getBatteryLevel() <= snapshot.getLowLevelThreshold()); + final boolean canShowWarning = !mLowWarningShownThisChargeCycle && !snapshot.isPowerSaver() + && snapshot.getBatteryLevel() <= snapshot.getLowLevelThreshold(); // Only show the severe warning once per charge cycle final boolean canShowSevereWarning = !mSevereWarningShownThisChargeCycle - && ((timeRemainingMillis != NO_ESTIMATE_AVAILABLE - && timeRemainingMillis < snapshot.getSevereThresholdMillis()) - || snapshot.getBatteryLevel() <= snapshot.getSevereLevelThreshold()); + && snapshot.getBatteryLevel() <= snapshot.getSevereLevelThreshold(); final boolean canShow = canShowWarning || canShowSevereWarning; @@ -712,8 +704,10 @@ public class PowerUI extends CoreStartable implements CommandQueue.Callbacks { int status = temp.getStatus(); if (status >= Temperature.THROTTLING_EMERGENCY) { - final Optional<StatusBar> statusBarOptional = mStatusBarOptionalLazy.get(); - if (!statusBarOptional.map(StatusBar::isDeviceInVrMode).orElse(false)) { + final Optional<CentralSurfaces> centralSurfacesOptional = + mCentralSurfacesOptionalLazy.get(); + if (!centralSurfacesOptional.map(CentralSurfaces::isDeviceInVrMode) + .orElse(false)) { mWarnings.showHighTemperatureWarning(); Slog.d(TAG, "SkinThermalEventListener: notifyThrottling was called " + ", current skin status = " + status diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt index 89735c3a547d..5d9361d201c1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt @@ -370,6 +370,7 @@ class FgsManagerController @Inject constructor( PowerExemptionManager.REASON_SYSTEM_UID, PowerExemptionManager.REASON_DEVICE_DEMO_MODE -> UIControl.HIDE_ENTRY + PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE, PowerExemptionManager.REASON_DEVICE_OWNER, PowerExemptionManager.REASON_PROFILE_OWNER, PowerExemptionManager.REASON_PROC_STATE_PERSISTENT, diff --git a/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt b/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt index 8afb7933aacc..95b4b725e4c6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt @@ -118,7 +118,7 @@ class HeaderPrivacyIconsController @Inject constructor( // If the privacy chip is visible, it means there were some indicators uiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_CLICK) if (safetyCenterEnabled) { - showSafetyHub() + showSafetyCenter() } else { privacyDialogController.showDialog(privacyChip.context) } @@ -131,16 +131,16 @@ class HeaderPrivacyIconsController @Inject constructor( updatePrivacyIconSlots() } - private fun showSafetyHub() { + private fun showSafetyCenter() { backgroundExecutor.execute { val usage = ArrayList(permGroupUsage()) privacyLogger.logUnfilteredPermGroupUsage(usage) - val startSafetyHub = Intent(Intent.ACTION_VIEW_SAFETY_HUB) - startSafetyHub.putParcelableArrayListExtra(PermissionManager.EXTRA_PERMISSION_USAGES, + val startSafetyCenter = Intent(Intent.ACTION_VIEW_SAFETY_CENTER_QS) + startSafetyCenter.putParcelableArrayListExtra(PermissionManager.EXTRA_PERMISSION_USAGES, usage) - startSafetyHub.flags = Intent.FLAG_ACTIVITY_NEW_TASK + startSafetyCenter.flags = Intent.FLAG_ACTIVITY_NEW_TASK uiExecutor.execute { - activityStarter.startActivity(startSafetyHub, true, + activityStarter.startActivity(startSafetyCenter, true, ActivityLaunchAnimator.Controller.fromView(privacyChip)) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index 3c7933f0d218..3ef72202a591 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -513,7 +513,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca mContainer.setExpansion(expansion); final float translationScaleY = (mInSplitShade ? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1); - boolean onKeyguardAndExpanded = isKeyguardState() && !mShowCollapsedOnKeyguard; + boolean onKeyguard = isKeyguardState(); + boolean onKeyguardAndExpanded = onKeyguard && !mShowCollapsedOnKeyguard; if (!mHeaderAnimating && !headerWillBeAnimating()) { getView().setTranslationY( onKeyguardAndExpanded @@ -547,6 +548,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca mHeader.updateResources(); } } + mQSPanelController.setIsOnKeyguard(onKeyguard); mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion); mQSFooterActionController.setExpansion(onKeyguardAndExpanded ? 1 : expansion); mQSPanelController.setRevealExpansion(expansion); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 5126fcb4c34d..b04d75273831 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -110,6 +110,8 @@ public class QSPanel extends LinearLayout implements Tunable { private final ArrayMap<View, Integer> mChildrenLayoutTop = new ArrayMap<>(); private final Rect mClippingRect = new Rect(); private boolean mUseNewFooter = false; + private ViewGroup mMediaHostView; + private boolean mShouldMoveMediaOnExpansion = true; public QSPanel(Context context, AttributeSet attrs) { super(context, attrs); @@ -289,9 +291,15 @@ public class QSPanel extends LinearLayout implements Tunable { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (move) { + int topOffset; + if (child == mMediaHostView && !mShouldMoveMediaOnExpansion) { + topOffset = 0; + } else { + topOffset = tileHeightOffset; + } int top = Objects.requireNonNull(mChildrenLayoutTop.get(child)); - child.setLeftTopRightBottom(child.getLeft(), top + tileHeightOffset, - child.getRight(), top + tileHeightOffset + child.getHeight()); + child.setLeftTopRightBottom(child.getLeft(), top + topOffset, + child.getRight(), top + topOffset + child.getHeight()); } if (child == mTileLayout) { move = true; @@ -463,6 +471,7 @@ public class QSPanel extends LinearLayout implements Tunable { if (!mUsingMediaPlayer) { return; } + mMediaHostView = hostView; ViewGroup newParent = horizontal ? mHorizontalLinearLayout : this; ViewGroup currentParent = (ViewGroup) hostView.getParent(); if (currentParent != newParent) { @@ -656,6 +665,19 @@ public class QSPanel extends LinearLayout implements Tunable { updatePadding(); } + /** + * Sets whether the media container should move during the expansion of the QS Panel. + * + * As the QS Panel expands and the QS unsquish, the views below the QS tiles move to adapt to + * the new height of the QS tiles. + * + * In some cases this might not be wanted for media. One example is when there is a transition + * animation of the media container happening on split shade lock screen. + */ + public void setShouldMoveMediaOnExpansion(boolean shouldMoveMediaOnExpansion) { + mShouldMoveMediaOnExpansion = shouldMoveMediaOnExpansion; + } + private class H extends Handler { private static final int ANNOUNCE_FOR_ACCESSIBILITY = 1; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java index 3172aa9592dd..6572daa91269 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java @@ -419,6 +419,16 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr return mView.getBrightnessView(); } + /** Sets whether we are currently on lock screen. */ + public void setIsOnKeyguard(boolean isOnKeyguard) { + boolean isOnSplitShadeLockscreen = mShouldUseSplitNotificationShade && isOnKeyguard; + // When the split shade is expanding on lockscreen, the media container transitions from the + // lockscreen to QS. + // We have to prevent the media container position from moving during the transition to have + // a smooth translation animation without stuttering. + mView.setShouldMoveMediaOnExpansion(!isOnSplitShadeLockscreen); + } + /** */ public static final class TileRecord { public TileRecord(QSTile tile, com.android.systemui.plugins.qs.QSTileView tileView) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index c69307548b6e..47af7de9118d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -53,7 +53,7 @@ import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.phone.AutoTileManager; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; @@ -102,7 +102,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D private final StatusBarIconController mIconController; private final ArrayList<QSFactory> mQsFactories = new ArrayList<>(); private int mCurrentUser; - private final Optional<StatusBar> mStatusBarOptional; + private final Optional<CentralSurfaces> mCentralSurfacesOptional; private Context mUserContext; private UserTracker mUserTracker; private SecureSettings mSecureSettings; @@ -121,7 +121,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D Provider<AutoTileManager> autoTiles, DumpManager dumpManager, BroadcastDispatcher broadcastDispatcher, - Optional<StatusBar> statusBarOptional, + Optional<CentralSurfaces> centralSurfacesOptional, QSLogger qsLogger, UiEventLogger uiEventLogger, UserTracker userTracker, @@ -143,7 +143,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D mTileLifeCycleManagerFactory = tileLifecycleManagerFactory; mInstanceIdSequence = new InstanceIdSequence(MAX_QS_INSTANCE_ID); - mStatusBarOptional = statusBarOptional; + mCentralSurfacesOptional = centralSurfacesOptional; mQsFactories.add(defaultFactory); pluginManager.addPluginListener(this, QSFactory.class, true); @@ -227,17 +227,17 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D @Override public void collapsePanels() { - mStatusBarOptional.ifPresent(StatusBar::postAnimateCollapsePanels); + mCentralSurfacesOptional.ifPresent(CentralSurfaces::postAnimateCollapsePanels); } @Override public void forceCollapsePanels() { - mStatusBarOptional.ifPresent(StatusBar::postAnimateForceCollapsePanels); + mCentralSurfacesOptional.ifPresent(CentralSurfaces::postAnimateForceCollapsePanels); } @Override public void openPanels() { - mStatusBarOptional.ifPresent(StatusBar::postAnimateOpenPanels); + mCentralSurfacesOptional.ifPresent(CentralSurfaces::postAnimateOpenPanels); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java index 597f7b7053a2..f389df097d7d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java @@ -26,7 +26,7 @@ import android.util.Log; import com.android.systemui.Dependency; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.shared.recents.IOverviewProxy; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import java.util.Optional; @@ -42,7 +42,7 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation { private final static String TAG = "OverviewProxyRecentsImpl"; @Nullable - private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; + private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; private Context mContext; private Handler mHandler; @@ -51,8 +51,8 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation { @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @Inject - public OverviewProxyRecentsImpl(Lazy<Optional<StatusBar>> statusBarOptionalLazy) { - mStatusBarOptionalLazy = statusBarOptionalLazy; + public OverviewProxyRecentsImpl(Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy) { + mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; } @Override @@ -109,9 +109,10 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation { } }; // Preload only if device for current user is unlocked - final Optional<StatusBar> statusBarOptional = mStatusBarOptionalLazy.get(); - if (statusBarOptional.map(StatusBar::isKeyguardShowing).orElse(false)) { - statusBarOptional.get().executeRunnableDismissingKeyguard(() -> { + final Optional<CentralSurfaces> centralSurfacesOptional = + mCentralSurfacesOptionalLazy.get(); + if (centralSurfacesOptional.map(CentralSurfaces::isKeyguardShowing).orElse(false)) { + centralSurfacesOptional.get().executeRunnableDismissingKeyguard(() -> { mHandler.post(toggleRecents); }, null, true /* dismissShade */, false /* afterKeyguardGone */, true /* deferred */); diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 7ceaee5fb7bb..a3dea1c68b14 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -102,7 +102,7 @@ import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.NotificationPanelViewController; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarWindowCallback; import com.android.systemui.statusbar.policy.CallbackController; import com.android.wm.shell.back.BackAnimation; @@ -146,7 +146,7 @@ public class OverviewProxyService extends CurrentUserTracker implements private final Context mContext; private final Optional<Pip> mPipOptional; - private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; + private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; private final Optional<SplitScreen> mSplitScreenOptional; private SysUiState mSysUiState; private final Handler mHandler; @@ -186,7 +186,7 @@ public class OverviewProxyService extends CurrentUserTracker implements @Override public void startScreenPinning(int taskId) { verifyCallerAndClearCallingIdentityPostMain("startScreenPinning", () -> - mStatusBarOptionalLazy.get().ifPresent( + mCentralSurfacesOptionalLazy.get().ifPresent( statusBar -> statusBar.showScreenPinningRequest(taskId, false /* allowCancel */))); } @@ -207,9 +207,9 @@ public class OverviewProxyService extends CurrentUserTracker implements public void onStatusBarMotionEvent(MotionEvent event) { verifyCallerAndClearCallingIdentity("onStatusBarMotionEvent", () -> { // TODO move this logic to message queue - mStatusBarOptionalLazy.get().ifPresent(statusBar -> { + mCentralSurfacesOptionalLazy.get().ifPresent(centralSurfaces -> { if (event.getActionMasked() == ACTION_DOWN) { - statusBar.getPanelController().startExpandLatencyTracking(); + centralSurfaces.getPanelController().startExpandLatencyTracking(); } mHandler.post(() -> { int action = event.getActionMasked(); @@ -217,7 +217,7 @@ public class OverviewProxyService extends CurrentUserTracker implements mInputFocusTransferStarted = true; mInputFocusTransferStartY = event.getY(); mInputFocusTransferStartMillis = event.getEventTime(); - statusBar.onInputFocusTransfer( + centralSurfaces.onInputFocusTransfer( mInputFocusTransferStarted, false /* cancel */, 0 /* velocity */); } @@ -225,7 +225,7 @@ public class OverviewProxyService extends CurrentUserTracker implements mInputFocusTransferStarted = false; float velocity = (event.getY() - mInputFocusTransferStartY) / (event.getEventTime() - mInputFocusTransferStartMillis); - statusBar.onInputFocusTransfer(mInputFocusTransferStarted, + centralSurfaces.onInputFocusTransfer(mInputFocusTransferStarted, action == ACTION_CANCEL, velocity); } @@ -401,7 +401,7 @@ public class OverviewProxyService extends CurrentUserTracker implements @Override public void toggleNotificationPanel() { verifyCallerAndClearCallingIdentityPostMain("toggleNotificationPanel", () -> - mStatusBarOptionalLazy.get().ifPresent(StatusBar::togglePanel)); + mCentralSurfacesOptionalLazy.get().ifPresent(CentralSurfaces::togglePanel)); } @@ -555,7 +555,7 @@ public class OverviewProxyService extends CurrentUserTracker implements @Inject public OverviewProxyService(Context context, CommandQueue commandQueue, Lazy<NavigationBarController> navBarControllerLazy, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, NavigationModeController navModeController, NotificationShadeWindowController statusBarWinController, SysUiState sysUiState, Optional<Pip> pipOptional, @@ -573,7 +573,7 @@ public class OverviewProxyService extends CurrentUserTracker implements super(broadcastDispatcher); mContext = context; mPipOptional = pipOptional; - mStatusBarOptionalLazy = statusBarOptionalLazy; + mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mHandler = new Handler(); mNavBarControllerLazy = navBarControllerLazy; mStatusBarWinController = statusBarWinController; @@ -665,7 +665,7 @@ public class OverviewProxyService extends CurrentUserTracker implements final NavigationBarView navBarView = mNavBarControllerLazy.get().getNavigationBarView(mContext.getDisplayId()); final NotificationPanelViewController panelController = - mStatusBarOptionalLazy.get().get().getPanelController(); + mCentralSurfacesOptionalLazy.get().get().getPanelController(); if (SysUiState.DEBUG) { Log.d(TAG_OPS, "Updating sysui state flags: navBarFragment=" + navBarFragment + " navBarView=" + navBarView + " panelController=" + panelController); @@ -731,9 +731,9 @@ public class OverviewProxyService extends CurrentUserTracker implements public void cleanupAfterDeath() { if (mInputFocusTransferStarted) { mHandler.post(() -> { - mStatusBarOptionalLazy.get().ifPresent(statusBar -> { + mCentralSurfacesOptionalLazy.get().ifPresent(centralSurfaces -> { mInputFocusTransferStarted = false; - statusBar.onInputFocusTransfer(false, true /* cancel */, 0 /* velocity */); + centralSurfaces.onInputFocusTransfer(false, true /* cancel */, 0 /* velocity */); }); }); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java index 7f130cb203c0..15ad7798b3a3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java +++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java @@ -56,7 +56,7 @@ import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.WindowManagerWrapper; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.util.leak.RotationUtils; import java.util.ArrayList; @@ -70,7 +70,7 @@ public class ScreenPinningRequest implements View.OnClickListener, NavigationModeController.ModeChangedListener { private final Context mContext; - private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; + private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; private final AccessibilityManager mAccessibilityService; private final WindowManager mWindowManager; @@ -83,9 +83,11 @@ public class ScreenPinningRequest implements View.OnClickListener, private int taskId; @Inject - public ScreenPinningRequest(Context context, Lazy<Optional<StatusBar>> statusBarOptionalLazy) { + public ScreenPinningRequest( + Context context, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy) { mContext = context; - mStatusBarOptionalLazy = statusBarOptionalLazy; + mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mAccessibilityService = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); mWindowManager = (WindowManager) @@ -267,9 +269,10 @@ public class ScreenPinningRequest implements View.OnClickListener, .setVisibility(View.INVISIBLE); } - final Optional<StatusBar> statusBarOptional = mStatusBarOptionalLazy.get(); + final Optional<CentralSurfaces> centralSurfacesOptional = + mCentralSurfacesOptionalLazy.get(); NavigationBarView navigationBarView = - statusBarOptional.map(StatusBar::getNavigationBarView).orElse(null); + centralSurfacesOptional.map(CentralSurfaces::getNavigationBarView).orElse(null); final boolean recentsVisible = navigationBarView != null && navigationBarView.isRecentsButtonVisible(); boolean touchExplorationEnabled = mAccessibilityService.isTouchExplorationEnabled(); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java index f14044682b61..daaa897374cb 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java @@ -24,7 +24,7 @@ import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_ import static com.android.systemui.screenshot.ScreenshotController.EXTRA_DISALLOW_ENTER_PIP; import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ID; import static com.android.systemui.screenshot.ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED; -import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT; +import static com.android.systemui.statusbar.phone.CentralSurfaces.SYSTEM_DIALOG_REASON_SCREENSHOT; import android.app.ActivityOptions; import android.app.PendingIntent; @@ -36,7 +36,7 @@ import android.view.RemoteAnimationAdapter; import android.view.WindowManagerGlobal; import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import java.util.Optional; @@ -49,15 +49,15 @@ import javax.inject.Inject; public class ActionProxyReceiver extends BroadcastReceiver { private static final String TAG = "ActionProxyReceiver"; - private final StatusBar mStatusBar; + private final CentralSurfaces mCentralSurfaces; private final ActivityManagerWrapper mActivityManagerWrapper; private final ScreenshotSmartActions mScreenshotSmartActions; @Inject - public ActionProxyReceiver(Optional<StatusBar> statusBar, + public ActionProxyReceiver(Optional<CentralSurfaces> centralSurfacesOptional, ActivityManagerWrapper activityManagerWrapper, ScreenshotSmartActions screenshotSmartActions) { - mStatusBar = statusBar.orElse(null); + mCentralSurfaces = centralSurfacesOptional.orElse(null); mActivityManagerWrapper = activityManagerWrapper; mScreenshotSmartActions = screenshotSmartActions; } @@ -89,8 +89,8 @@ public class ActionProxyReceiver extends BroadcastReceiver { }; - if (mStatusBar != null) { - mStatusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null, + if (mCentralSurfaces != null) { + mCentralSurfaces.executeRunnableDismissingKeyguard(startActivityRunnable, null, true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */); } else { diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java index 991a68fb056a..7801c68586f1 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java @@ -54,7 +54,7 @@ import com.android.systemui.statusbar.policy.BrightnessMirrorController; import javax.inject.Inject; public class BrightnessController implements ToggleSlider.Listener, MirroredBrightnessController { - private static final String TAG = "StatusBar.BrightnessController"; + private static final String TAG = "CentralSurfaces.BrightnessController"; private static final int SLIDER_ANIMATION_DURATION = 3000; private static final int MSG_UPDATE_SLIDER = 1; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 645c5accb541..8a02e5952659 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -23,7 +23,7 @@ import static android.inputmethodservice.InputMethodService.IME_INVISIBLE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; -import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS; +import static com.android.systemui.statusbar.phone.CentralSurfaces.ONLY_CORE_APPS; import android.annotation.Nullable; import android.app.ITransientNotificationCallback; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt index 8366bddaab9f..17f42b1a3a43 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt @@ -38,7 +38,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.LSShadeTransitionLogger import com.android.systemui.statusbar.phone.NotificationPanelViewController import com.android.systemui.statusbar.phone.ScrimController -import com.android.systemui.statusbar.phone.StatusBar +import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.Utils import java.io.FileDescriptor @@ -73,7 +73,7 @@ class LockscreenShadeTransitionController @Inject constructor( private var useSplitShade: Boolean = false private lateinit var nsslController: NotificationStackScrollLayoutController lateinit var notificationPanelController: NotificationPanelViewController - lateinit var statusbar: StatusBar + lateinit var centralSurfaces: CentralSurfaces lateinit var qS: QS /** @@ -197,7 +197,7 @@ class LockscreenShadeTransitionController @Inject constructor( // Bind the click listener of the shelf to go to the full shade notificationShelfController.setOnClickListener { if (statusBarStateController.state == StatusBarState.KEYGUARD) { - statusbar.wakeUpIfDozing(SystemClock.uptimeMillis(), it, "SHADE_CLICK") + centralSurfaces.wakeUpIfDozing(SystemClock.uptimeMillis(), it, "SHADE_CLICK") goToLockedShade(it) } } @@ -224,7 +224,7 @@ class LockscreenShadeTransitionController @Inject constructor( if (nsslController.isInLockedDownShade()) { logger.logDraggedDownLockDownShade(startingChild) statusBarStateController.setLeaveOpenOnKeyguardHide(true) - statusbar.dismissKeyguardThenExecute(OnDismissAction { + centralSurfaces.dismissKeyguardThenExecute(OnDismissAction { nextHideKeyguardNeedsNoAnimation = true false }, cancelRunnable, false /* afterKeyguardGone */) @@ -342,9 +342,7 @@ class LockscreenShadeTransitionController @Inject constructor( qS.setTransitionToFullShadeAmount(field, qSDragProgress) notificationPanelController.setTransitionToFullShadeAmount(field, false /* animate */, 0 /* delay */) - // TODO: appear media also in split shade - val mediaAmount = if (useSplitShade) 0f else field - mediaHierarchyManager.setTransitionToFullShadeAmount(mediaAmount) + mediaHierarchyManager.setTransitionToFullShadeAmount(field) transitionToShadeAmountCommon(field) } } @@ -363,7 +361,7 @@ class LockscreenShadeTransitionController @Inject constructor( notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - scrimProgress) depthController.transitionToFullShadeProgress = scrimProgress udfpsKeyguardViewController?.setTransitionToFullShadeProgress(scrimProgress) - statusbar.setTransitionToFullShadeProgress(scrimProgress) + centralSurfaces.setTransitionToFullShadeProgress(scrimProgress) } private fun setDragDownAmountAnimated( @@ -463,7 +461,7 @@ class LockscreenShadeTransitionController @Inject constructor( animationHandler: ((Long) -> Unit)? = null, cancelAction: Runnable? = null ) { - if (statusbar.isShadeDisabled) { + if (centralSurfaces.isShadeDisabled) { cancelAction?.run() logger.logShadeDisabledOnGoToLockedShade() return @@ -505,7 +503,7 @@ class LockscreenShadeTransitionController @Inject constructor( cancelAction?.run() } logger.logShowBouncerOnGoToLockedShade() - statusbar.showBouncerWithDimissAndCancelIfKeyguard(onDismissAction, cancelHandler) + centralSurfaces.showBouncerWithDimissAndCancelIfKeyguard(onDismissAction, cancelHandler) draggedDownEntry = entry } else { logger.logGoingToLockedShade(animationHandler != null) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java index 01bdb401e00c..68d35f9679ed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java @@ -32,10 +32,10 @@ import android.util.Log; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.statusbar.dagger.StatusBarModule; +import com.android.systemui.statusbar.dagger.CentralSurfacesModule; import com.android.systemui.statusbar.notification.collection.NotifCollection; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins; -import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.util.time.SystemClock; import java.util.ArrayList; @@ -54,7 +54,7 @@ import javax.inject.Inject; @SuppressLint("OverrideAbstract") public class NotificationListener extends NotificationListenerWithPlugins { private static final String TAG = "NotificationListener"; - private static final boolean DEBUG = StatusBar.DEBUG; + private static final boolean DEBUG = CentralSurfaces.DEBUG; private static final long MAX_RANKING_DELAY_MILLIS = 500L; private final Context mContext; @@ -69,7 +69,7 @@ public class NotificationListener extends NotificationListenerWithPlugins { private long mSkippingRankingUpdatesSince = -1; /** - * Injected constructor. See {@link StatusBarModule}. + * Injected constructor. See {@link CentralSurfacesModule}. */ @Inject public NotificationListener( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index 3730d123021b..052c57e768fe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -16,9 +16,9 @@ package com.android.systemui.statusbar; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; -import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_MEDIA_FAKE_ARTWORK; -import static com.android.systemui.statusbar.phone.StatusBar.ENABLE_LOCKSCREEN_WALLPAPER; -import static com.android.systemui.statusbar.phone.StatusBar.SHOW_LOCKSCREEN_MEDIA_ARTWORK; +import static com.android.systemui.statusbar.phone.CentralSurfaces.DEBUG_MEDIA_FAKE_ARTWORK; +import static com.android.systemui.statusbar.phone.CentralSurfaces.ENABLE_LOCKSCREEN_WALLPAPER; +import static com.android.systemui.statusbar.phone.CentralSurfaces.SHOW_LOCKSCREEN_MEDIA_ARTWORK; import android.annotation.MainThread; import android.annotation.NonNull; @@ -55,7 +55,7 @@ import com.android.systemui.media.MediaData; import com.android.systemui.media.MediaDataManager; import com.android.systemui.media.SmartspaceMediaData; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.dagger.StatusBarModule; +import com.android.systemui.statusbar.dagger.CentralSurfacesModule; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -66,11 +66,11 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.Di import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.phone.BiometricUnlockController; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.LockscreenWallpaper; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ScrimState; -import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.Utils; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -131,7 +131,7 @@ public class NotificationMediaManager implements Dumpable { private final Context mContext; private final ArrayList<MediaListener> mMediaListeners; - private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; + private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; private final MediaArtworkProcessor mMediaArtworkProcessor; private final Set<AsyncTask<?, ?, ?>> mProcessArtworkTasks = new ArraySet<>(); @@ -172,11 +172,11 @@ public class NotificationMediaManager implements Dumpable { }; /** - * Injected constructor. See {@link StatusBarModule}. + * Injected constructor. See {@link CentralSurfacesModule}. */ public NotificationMediaManager( Context context, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, Lazy<NotificationShadeWindowController> notificationShadeWindowController, NotificationVisibilityProvider visibilityProvider, NotificationEntryManager notificationEntryManager, @@ -193,7 +193,7 @@ public class NotificationMediaManager implements Dumpable { mKeyguardBypassController = keyguardBypassController; mMediaListeners = new ArrayList<>(); // TODO: use KeyguardStateController#isOccluded to remove this dependency - mStatusBarOptionalLazy = statusBarOptionalLazy; + mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mNotificationShadeWindowController = notificationShadeWindowController; mVisibilityProvider = visibilityProvider; mEntryManager = notificationEntryManager; @@ -575,7 +575,7 @@ public class NotificationMediaManager implements Dumpable { * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper. */ public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) { - Trace.beginSection("StatusBar#updateMediaMetaData"); + Trace.beginSection("CentralSurfaces#updateMediaMetaData"); if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) { Trace.endSection(); return; @@ -653,7 +653,8 @@ public class NotificationMediaManager implements Dumpable { NotificationShadeWindowController windowController = mNotificationShadeWindowController.get(); boolean hideBecauseOccluded = - mStatusBarOptionalLazy.get().map(StatusBar::isOccluded).orElse(false); + mCentralSurfacesOptionalLazy.get() + .map(CentralSurfaces::isOccluded).orElse(false); final boolean hasArtwork = artworkDrawable != null; mColorExtractor.setHasMediaArtwork(hasMediaArtwork); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java index 17bf346fa22b..3b3b5a2d05f9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java @@ -19,7 +19,7 @@ import com.android.systemui.statusbar.notification.row.ActivatableNotificationVi import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; /** - * An abstraction of something that presents notifications, e.g. StatusBar. Contains methods + * An abstraction of something that presents notifications, e.g. CentralSurfaces. Contains methods * for both querying the state of the system (some modularised piece of functionality may * want to act differently based on e.g. whether the presenter is visible to the user or not) and * for affecting the state of the system (e.g. starting an intent, given that the presenter may diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index 2b5453a56434..94a6d3e99842 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -55,7 +55,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.dagger.StatusBarDependenciesModule; +import com.android.systemui.statusbar.dagger.CentralSurfacesDependenciesModule; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -64,7 +64,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry. import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.RemoteInputView; import com.android.systemui.util.DumpUtilsKt; @@ -103,7 +103,7 @@ public class NotificationRemoteInputManager implements Dumpable { private final Handler mMainHandler; private final ActionClickLogger mLogger; - private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; + private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; protected final Context mContext; protected final NotifPipelineFlags mNotifPipelineFlags; @@ -125,8 +125,8 @@ public class NotificationRemoteInputManager implements Dumpable { @Override public boolean onInteraction( View view, PendingIntent pendingIntent, RemoteViews.RemoteResponse response) { - mStatusBarOptionalLazy.get().ifPresent( - statusBar -> statusBar.wakeUpIfDozing( + mCentralSurfacesOptionalLazy.get().ifPresent( + centralSurfaces -> centralSurfaces.wakeUpIfDozing( SystemClock.uptimeMillis(), view, "NOTIFICATION_CLICK")); final NotificationEntry entry = getNotificationForParent(view.getParent()); @@ -253,7 +253,7 @@ public class NotificationRemoteInputManager implements Dumpable { }; /** - * Injected constructor. See {@link StatusBarDependenciesModule}. + * Injected constructor. See {@link CentralSurfacesDependenciesModule}. */ public NotificationRemoteInputManager( Context context, @@ -263,7 +263,7 @@ public class NotificationRemoteInputManager implements Dumpable { NotificationVisibilityProvider visibilityProvider, NotificationEntryManager notificationEntryManager, RemoteInputNotificationRebuilder rebuilder, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, StatusBarStateController statusBarStateController, @Main Handler mainHandler, RemoteInputUriController remoteInputUriController, @@ -276,7 +276,7 @@ public class NotificationRemoteInputManager implements Dumpable { mSmartReplyController = smartReplyController; mVisibilityProvider = visibilityProvider; mEntryManager = notificationEntryManager; - mStatusBarOptionalLazy = statusBarOptionalLazy; + mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mMainHandler = mainHandler; mLogger = logger; mBarService = IStatusBarService.Stub.asInterface( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java index 4f70fdb0d978..3b1fa1779c17 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar; import android.view.View; +import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController; import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope; import com.android.systemui.statusbar.notification.stack.AmbientState; @@ -25,7 +26,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationIconContainer; -import com.android.systemui.statusbar.phone.StatusBarNotificationPresenter; import javax.inject.Inject; @@ -114,8 +114,8 @@ public class NotificationShelfController { return mView.getIntrinsicHeight(); } - public void setOnActivatedListener(StatusBarNotificationPresenter presenter) { - mView.setOnActivatedListener(presenter); + public void setOnActivatedListener(ActivatableNotificationView.OnActivatedListener listener) { + mView.setOnActivatedListener(listener); } public void setOnClickListener(View.OnClickListener onClickListener) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java index 092e86daddb8..054543c7d2b1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java @@ -32,7 +32,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.dagger.StatusBarModule; +import com.android.systemui.statusbar.dagger.CentralSurfacesModule; import com.android.systemui.statusbar.notification.AssistantFeedbackController; import com.android.systemui.statusbar.notification.DynamicChildBindController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; @@ -45,7 +45,6 @@ import com.android.systemui.statusbar.notification.collection.legacy.VisualStabi import com.android.systemui.statusbar.notification.collection.render.NotifStackController; import com.android.systemui.statusbar.notification.collection.render.NotifStats; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -97,7 +96,6 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle private final Optional<Bubbles> mBubblesOptional; private final DynamicPrivacyController mDynamicPrivacyController; private final KeyguardBypassController mBypassController; - private final ForegroundServiceSectionController mFgsSectionController; private final NotifPipelineFlags mNotifPipelineFlags; private AssistantFeedbackController mAssistantFeedbackController; private final KeyguardStateController mKeyguardStateController; @@ -115,7 +113,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle private boolean mIsHandleDynamicPrivacyChangeScheduled; /** - * Injected constructor. See {@link StatusBarModule}. + * Injected constructor. See {@link CentralSurfacesModule}. */ public NotificationViewHierarchyManager( Context context, @@ -129,7 +127,6 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle KeyguardBypassController bypassController, Optional<Bubbles> bubblesOptional, DynamicPrivacyController privacyController, - ForegroundServiceSectionController fgsSectionController, DynamicChildBindController dynamicChildBindController, LowPriorityInflationHelper lowPriorityInflationHelper, AssistantFeedbackController assistantFeedbackController, @@ -145,7 +142,6 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle mVisualStabilityManager = visualStabilityManager; mStatusBarStateController = (SysuiStatusBarStateController) statusBarStateController; mEntryManager = notificationEntryManager; - mFgsSectionController = fgsSectionController; mNotifPipelineFlags = notifPipelineFlags; Resources res = context.getResources(); mAlwaysExpandNonGroupedNotification = @@ -417,8 +413,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle && mBubblesOptional.get().isBubbleNotificationSuppressedFromShade( ent.getKey(), ent.getSbn().getGroupKey()); if (ent.isRowDismissed() || ent.isRowRemoved() - || isBubbleNotificationSuppressedFromShade - || mFgsSectionController.hasEntry(ent)) { + || isBubbleNotificationSuppressedFromShade) { // we want to suppress removed notifications because they could // temporarily become children if they were isolated before. return true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateController.java index 2e1762a26b7e..78077386179a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateController.java @@ -20,17 +20,17 @@ import android.view.View; import com.android.systemui.plugins.qs.QS; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; /** * Calculates and moves the QS frame vertically. */ public abstract class QsFrameTranslateController { - protected StatusBar mStatusBar; + protected CentralSurfaces mCentralSurfaces; - public QsFrameTranslateController(StatusBar statusBar) { - mStatusBar = statusBar; + public QsFrameTranslateController(CentralSurfaces centralSurfaces) { + mCentralSurfaces = centralSurfaces; } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateImpl.java index c15679709c3d..33e224579bef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateImpl.java @@ -21,7 +21,7 @@ import android.view.View; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.plugins.qs.QS; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import javax.inject.Inject; @@ -32,8 +32,8 @@ import javax.inject.Inject; public class QsFrameTranslateImpl extends QsFrameTranslateController { @Inject - public QsFrameTranslateImpl(StatusBar statusBar) { - super(statusBar); + public QsFrameTranslateImpl(CentralSurfaces centralSurfaces) { + super(centralSurfaces); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java index 4ad01aab98a7..058edda20971 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java @@ -25,7 +25,7 @@ import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dumpable; import com.android.systemui.dump.DumpManager; -import com.android.systemui.statusbar.dagger.StatusBarModule; +import com.android.systemui.statusbar.dagger.CentralSurfacesModule; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; @@ -45,7 +45,7 @@ public class SmartReplyController implements Dumpable { private Callback mCallback; /** - * Injected constructor. See {@link StatusBarModule}. + * Injected constructor. See {@link CentralSurfacesModule}. */ public SmartReplyController( DumpManager dumpManager, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index 02870a382056..2763bd711338 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -420,8 +420,9 @@ public class StatusBarStateControllerImpl implements * notified before unranked, and we will sort ranked listeners from low to high * * @deprecated This method exists only to solve latent inter-dependencies from refactoring - * StatusBarState out of StatusBar.java. Any new listeners should be built not to need ranking - * (i.e., they are non-dependent on the order of operations of StatusBarState listeners). + * StatusBarState out of CentralSurfaces.java. Any new listeners should be built not to need + * ranking (i.e., they are non-dependent on the order of operations of StatusBarState + * listeners). */ @Deprecated @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java index f0b2c2d54dbe..2b3190159ecd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java @@ -25,7 +25,7 @@ import android.view.WindowInsetsController.Appearance; import android.view.WindowInsetsController.Behavior; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import java.lang.annotation.Retention; @@ -51,8 +51,9 @@ public interface SysuiStatusBarStateController extends StatusBarStateController * notified before unranked, and we will sort ranked listeners from low to high * * @deprecated This method exists only to solve latent inter-dependencies from refactoring - * StatusBarState out of StatusBar.java. Any new listeners should be built not to need ranking - * (i.e., they are non-dependent on the order of operations of StatusBarState listeners). + * StatusBarState out of CentralSurfaces.java. Any new listeners should be built not to need + * ranking (i.e., they are non-dependent on the order of operations of StatusBarState + * listeners). */ @Deprecated void addCallback(StateListener listener, int rank); @@ -91,7 +92,7 @@ public interface SysuiStatusBarStateController extends StatusBarStateController int getCurrentOrUpcomingState(); /** - * Update the dozing state from {@link StatusBar}'s perspective + * Update the dozing state from {@link CentralSurfaces}'s perspective * @param isDozing well, are we dozing? * @return {@code true} if the state changed, else {@code false} */ @@ -116,7 +117,7 @@ public interface SysuiStatusBarStateController extends StatusBarStateController void setAndInstrumentDozeAmount(View view, float dozeAmount, boolean animated); /** - * Update the expanded state from {@link StatusBar}'s perspective + * Update the expanded state from {@link CentralSurfaces}'s perspective * @param expanded are we expanded? * @return {@code true} if the state changed, else {@code false} */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java index fe5a69996eb7..41d2b655d805 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java @@ -843,7 +843,7 @@ public class MobileSignalController extends SignalController<MobileState, Mobile } } - /** Box for StatusBar icon info */ + /** Box for status bar icon info */ private static final class SbInfo { final boolean showTriangle; final int ratTypeIcon; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt index d65fa3acfa37..a62a152ab7f4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt @@ -21,18 +21,18 @@ import com.android.systemui.fragments.FragmentHostManager import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions import com.android.systemui.statusbar.phone.PhoneStatusBarView import com.android.systemui.statusbar.phone.PhoneStatusBarViewController -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment import com.android.systemui.statusbar.window.StatusBarWindowController import java.lang.IllegalStateException import javax.inject.Inject /** - * Responsible for creating the StatusBar window and initializing the root components of that window - * (see [CollapsedStatusBarFragment]) + * Responsible for creating the status bar window and initializing the root components of that + * window (see [CollapsedStatusBarFragment]) */ -@StatusBarScope +@CentralSurfacesScope class StatusBarInitializer @Inject constructor( private val windowController: StatusBarWindowController ) { @@ -43,7 +43,7 @@ class StatusBarInitializer @Inject constructor( * Creates the status bar window and root views, and initializes the component */ fun initializeStatusBar( - sbComponent: StatusBarComponent + centralSurfacesComponent: CentralSurfacesComponent ) { windowController.fragmentHostManager.addTagListener( CollapsedStatusBarFragment.TAG, @@ -64,7 +64,7 @@ class StatusBarInitializer @Inject constructor( }).fragmentManager .beginTransaction() .replace(R.id.status_bar_container, - sbComponent.createCollapsedStatusBarFragment(), + centralSurfacesComponent.createCollapsedStatusBarFragment(), CollapsedStatusBarFragment.TAG) .commit() } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java index c687e8282c7c..83290af24f2a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java @@ -60,11 +60,10 @@ import com.android.systemui.statusbar.notification.collection.legacy.Notificatio import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; -import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.ManagedProfileController; import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl; -import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl; import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback; @@ -88,12 +87,13 @@ import dagger.Module; import dagger.Provides; /** - * This module provides instances needed to construct {@link StatusBar}. These are moved to this - * separate from {@link StatusBarModule} module so that components that wish to build their own - * version of StatusBar can include just dependencies, without injecting StatusBar itself. + * This module provides instances needed to construct {@link CentralSurfaces}. These are moved to + * this separate from {@link CentralSurfacesModule} module so that components that wish to build + * their own version of CentralSurfaces can include just dependencies, without injecting + * CentralSurfaces itself. */ @Module -public interface StatusBarDependenciesModule { +public interface CentralSurfacesDependenciesModule { /** */ @SysUISingleton @Provides @@ -105,7 +105,7 @@ public interface StatusBarDependenciesModule { NotificationVisibilityProvider visibilityProvider, NotificationEntryManager notificationEntryManager, RemoteInputNotificationRebuilder rebuilder, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, StatusBarStateController statusBarStateController, Handler mainHandler, RemoteInputUriController remoteInputUriController, @@ -120,7 +120,7 @@ public interface StatusBarDependenciesModule { visibilityProvider, notificationEntryManager, rebuilder, - statusBarOptionalLazy, + centralSurfacesOptionalLazy, statusBarStateController, mainHandler, remoteInputUriController, @@ -134,7 +134,7 @@ public interface StatusBarDependenciesModule { @Provides static NotificationMediaManager provideNotificationMediaManager( Context context, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, Lazy<NotificationShadeWindowController> notificationShadeWindowController, NotificationVisibilityProvider visibilityProvider, NotificationEntryManager notificationEntryManager, @@ -148,7 +148,7 @@ public interface StatusBarDependenciesModule { DumpManager dumpManager) { return new NotificationMediaManager( context, - statusBarOptionalLazy, + centralSurfacesOptionalLazy, notificationShadeWindowController, visibilityProvider, notificationEntryManager, @@ -198,7 +198,6 @@ public interface StatusBarDependenciesModule { KeyguardBypassController bypassController, Optional<Bubbles> bubblesOptional, DynamicPrivacyController privacyController, - ForegroundServiceSectionController fgsSectionController, DynamicChildBindController dynamicChildBindController, LowPriorityInflationHelper lowPriorityInflationHelper, AssistantFeedbackController assistantFeedbackController, @@ -217,7 +216,6 @@ public interface StatusBarDependenciesModule { bypassController, bubblesOptional, privacyController, - fgsSectionController, dynamicChildBindController, lowPriorityInflationHelper, assistantFeedbackController, @@ -261,6 +259,7 @@ public interface StatusBarDependenciesModule { @Provides @SysUISingleton static OngoingCallController provideOngoingCallController( + Context context, CommonNotifCollection notifCollection, SystemClock systemClock, ActivityStarter activityStarter, @@ -284,6 +283,7 @@ public interface StatusBarDependenciesModule { : Optional.empty(); OngoingCallController ongoingCallController = new OngoingCallController( + context, notifCollection, ongoingCallFlags, systemClock, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesModule.java index ad5ef2043ccd..99d4b2e525d1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesModule.java @@ -23,7 +23,7 @@ import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule; import dagger.Module; /** */ -@Module(includes = {StatusBarPhoneModule.class, StatusBarDependenciesModule.class, +@Module(includes = {StatusBarPhoneModule.class, CentralSurfacesDependenciesModule.class, NotificationsModule.class, NotificationRowModule.class}) -public interface StatusBarModule { +public interface CentralSurfacesModule { } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StartStatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StartCentralSurfacesModule.kt index 46c1abb859b3..fe55dea7333a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StartStatusBarModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StartCentralSurfacesModule.kt @@ -17,17 +17,17 @@ package com.android.systemui.statusbar.dagger import com.android.systemui.CoreStartable -import com.android.systemui.statusbar.phone.StatusBar +import com.android.systemui.statusbar.phone.CentralSurfaces import dagger.Binds import dagger.Module import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap @Module -interface StartStatusBarModule { - /** Start the StatusBar */ +interface StartCentralSurfacesModule { + /** Start the CentralSurfaces */ @Binds @IntoMap - @ClassKey(StatusBar::class) - abstract fun bindsStatusBar(statusBar: StatusBar): CoreStartable -}
\ No newline at end of file + @ClassKey(CentralSurfaces::class) + abstract fun bindsCentralSurfaces(centralSurfaces: CentralSurfaces): CoreStartable +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/GenericGestureDetector.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/GenericGestureDetector.kt index 76766b0d0ef0..3a4731a5a6aa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/GenericGestureDetector.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/GenericGestureDetector.kt @@ -22,6 +22,7 @@ import android.os.Looper import android.view.Choreographer import android.view.Display import android.view.InputEvent +import android.view.MotionEvent import com.android.systemui.shared.system.InputChannelCompat import com.android.systemui.shared.system.InputMonitorCompat @@ -43,13 +44,17 @@ abstract class GenericGestureDetector( * Active callbacks, each associated with a tag. Gestures will only be monitored if * [callbacks.size] > 0. */ - private val callbacks: MutableMap<String, () -> Unit> = mutableMapOf() + private val callbacks: MutableMap<String, (MotionEvent) -> Unit> = mutableMapOf() private var inputMonitor: InputMonitorCompat? = null private var inputReceiver: InputChannelCompat.InputEventReceiver? = null - /** Adds a callback that will be triggered when the tap gesture is detected. */ - fun addOnGestureDetectedCallback(tag: String, callback: () -> Unit) { + /** + * Adds a callback that will be triggered when the tap gesture is detected. + * + * The callback receive the last motion event in the gesture. + */ + fun addOnGestureDetectedCallback(tag: String, callback: (MotionEvent) -> Unit) { val callbacksWasEmpty = callbacks.isEmpty() callbacks[tag] = callback if (callbacksWasEmpty) { @@ -68,9 +73,12 @@ abstract class GenericGestureDetector( /** Triggered each time a touch event occurs (and at least one callback is registered). */ abstract fun onInputEvent(ev: InputEvent) - /** Should be called by subclasses when their specific gesture is detected. */ - internal fun onGestureDetected() { - callbacks.values.forEach { it.invoke() } + /** + * Should be called by subclasses when their specific gesture is detected with the last motion + * event in the gesture. + */ + internal fun onGestureDetected(e: MotionEvent) { + callbacks.values.forEach { it.invoke(e) } } /** Start listening to touch events. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt index fcb285a50ae7..6115819b967a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt @@ -80,7 +80,7 @@ open class SwipeStatusBarAwayGestureHandler @Inject constructor( ) { monitoringCurrentTouch = false logger.logGestureDetected(ev.y.toInt()) - onGestureDetected() + onGestureDetected(ev) } } ACTION_CANCEL, ACTION_UP -> { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt index 4107ce2593f1..7ffb07aa77d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt @@ -33,8 +33,8 @@ class TapGestureDetector @Inject constructor( ) : GenericGestureDetector(TapGestureDetector::class.simpleName!!) { private val gestureListener = object : GestureDetector.SimpleOnGestureListener() { - override fun onSingleTapUp(e: MotionEvent?): Boolean { - onGestureDetected() + override fun onSingleTapUp(e: MotionEvent): Boolean { + onGestureDetected(e) return true } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ForegroundServiceDismissalFeatureController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ForegroundServiceDismissalFeatureController.kt deleted file mode 100644 index 314051c8ce6c..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ForegroundServiceDismissalFeatureController.kt +++ /dev/null @@ -1,49 +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.systemui.statusbar.notification - -import android.content.Context -import android.provider.DeviceConfig -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_ALLOW_FGS_DISMISSAL -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.util.DeviceConfigProxy -import javax.inject.Inject - -private var sIsEnabled: Boolean? = null - -/** - * Feature controller for NOTIFICATIONS_ALLOW_FGS_DISMISSAL config. - */ -// TODO: this is really boilerplatey, make a base class that just wraps the device config -@SysUISingleton -class ForegroundServiceDismissalFeatureController @Inject constructor( - val proxy: DeviceConfigProxy, - val context: Context -) { - fun isForegroundServiceDismissalEnabled(): Boolean { - return isEnabled(proxy) - } -} - -private fun isEnabled(proxy: DeviceConfigProxy): Boolean { - if (sIsEnabled == null) { - sIsEnabled = proxy.getBoolean( - DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_ALLOW_FGS_DISMISSAL, false) - } - - return sIsEnabled!! -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java index da706215863e..392145ad306a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java @@ -24,7 +24,7 @@ import android.view.View; import com.android.systemui.DejankUtils; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.wm.shell.bubbles.Bubbles; import java.util.Optional; @@ -39,7 +39,7 @@ public final class NotificationClicker implements View.OnClickListener { private static final String TAG = "NotificationClicker"; private final NotificationClickerLogger mLogger; - private final Optional<StatusBar> mStatusBarOptional; + private final Optional<CentralSurfaces> mCentralSurfacesOptional; private final Optional<Bubbles> mBubblesOptional; private final NotificationActivityStarter mNotificationActivityStarter; @@ -53,11 +53,11 @@ public final class NotificationClicker implements View.OnClickListener { private NotificationClicker( NotificationClickerLogger logger, - Optional<StatusBar> statusBarOptional, + Optional<CentralSurfaces> centralSurfacesOptional, Optional<Bubbles> bubblesOptional, NotificationActivityStarter notificationActivityStarter) { mLogger = logger; - mStatusBarOptional = statusBarOptional; + mCentralSurfacesOptional = centralSurfacesOptional; mBubblesOptional = bubblesOptional; mNotificationActivityStarter = notificationActivityStarter; } @@ -69,7 +69,7 @@ public final class NotificationClicker implements View.OnClickListener { return; } - mStatusBarOptional.ifPresent(statusBar -> statusBar.wakeUpIfDozing( + mCentralSurfacesOptional.ifPresent(centralSurfaces -> centralSurfaces.wakeUpIfDozing( SystemClock.uptimeMillis(), v, "NOTIFICATION_CLICK")); final ExpandableNotificationRow row = (ExpandableNotificationRow) v; @@ -137,13 +137,13 @@ public final class NotificationClicker implements View.OnClickListener { /** Builds an instance. */ public NotificationClicker build( - Optional<StatusBar> statusBarOptional, + Optional<CentralSurfaces> centralSurfacesOptional, Optional<Bubbles> bubblesOptional, NotificationActivityStarter notificationActivityStarter ) { return new NotificationClicker( mLogger, - statusBarOptional, + centralSurfacesOptional, bubblesOptional, notificationActivityStarter); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index f97b936605f6..ac5beece880e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -111,7 +111,6 @@ public class NotificationEntryManager implements private final Lazy<NotificationRowBinder> mNotificationRowBinderLazy; private final Lazy<NotificationRemoteInputManager> mRemoteInputManagerLazy; private final LeakDetector mLeakDetector; - private final ForegroundServiceDismissalFeatureController mFgsFeatureController; private final IStatusBarService mStatusBarService; private final NotifLiveDataStoreImpl mNotifLiveDataStore; private final DumpManager mDumpManager; @@ -159,7 +158,6 @@ public class NotificationEntryManager implements Lazy<NotificationRowBinder> notificationRowBinderLazy, Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy, LeakDetector leakDetector, - ForegroundServiceDismissalFeatureController fgsFeatureController, IStatusBarService statusBarService, NotifLiveDataStoreImpl notifLiveDataStore, DumpManager dumpManager @@ -170,7 +168,6 @@ public class NotificationEntryManager implements mNotificationRowBinderLazy = notificationRowBinderLazy; mRemoteInputManagerLazy = notificationRemoteInputManagerLazy; mLeakDetector = leakDetector; - mFgsFeatureController = fgsFeatureController; mStatusBarService = statusBarService; mNotifLiveDataStore = notifLiveDataStore; mDumpManager = dumpManager; @@ -958,7 +955,7 @@ public class NotificationEntryManager implements Trace.endSection(); } - /** dump the current active notification list. Called from StatusBar */ + /** dump the current active notification list. Called from CentralSurfaces */ public void dump(PrintWriter pw, String indent) { pw.println("NotificationEntryManager (Legacy)"); int filteredLen = mSortedAndFiltered.size(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt index 9da7d21886ab..2c1296f34a42 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt @@ -8,12 +8,15 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.stack.NotificationListContainer import com.android.systemui.statusbar.phone.HeadsUpManagerPhone import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent import com.android.systemui.statusbar.policy.HeadsUpUtil +import javax.inject.Inject import kotlin.math.ceil import kotlin.math.max /** A provider of [NotificationLaunchAnimatorController]. */ -class NotificationLaunchAnimatorControllerProvider( +@CentralSurfacesComponent.CentralSurfacesScope +class NotificationLaunchAnimatorControllerProvider @Inject constructor( private val notificationShadeWindowViewController: NotificationShadeWindowViewController, private val notificationListContainer: NotificationListContainer, private val headsUpManager: HeadsUpManagerPhone, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt index 5dc0dcc4d717..c71eade79cdf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt @@ -23,7 +23,7 @@ import android.util.Log import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener -import com.android.systemui.statusbar.phone.StatusBar +import com.android.systemui.statusbar.phone.CentralSurfaces import javax.inject.Inject @SysUISingleton @@ -39,7 +39,7 @@ class TargetSdkResolver @Inject constructor( } private fun resolveNotificationSdk(sbn: StatusBarNotification): Int { - val pmUser = StatusBar.getPackageManagerForUser(context, sbn.user.identifier) + val pmUser = CentralSurfaces.getPackageManagerForUser(context, sbn.user.identifier) var targetSdk = 0 // Extract target SDK version. try { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationPresenterExtensions.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationPresenterExtensions.java index 4ee08ed4899f..bdbb0eb48e8a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationPresenterExtensions.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationPresenterExtensions.java @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.notification.collection.legacy; -import static com.android.systemui.statusbar.phone.StatusBar.SPEW; +import static com.android.systemui.statusbar.phone.CentralSurfaces.SPEW; import android.service.notification.StatusBarNotification; import android.util.Log; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifPanelEventSource.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifPanelEventSource.kt index 920d3c4cbe55..470737e3b772 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifPanelEventSource.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifPanelEventSource.kt @@ -17,8 +17,8 @@ package com.android.systemui.statusbar.notification.collection.render import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.phone.NotificationPanelViewController -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope import com.android.systemui.util.ListenerSet import dagger.Binds import dagger.Module @@ -67,18 +67,18 @@ object StatusBarNotifPanelEventSourceModule { @JvmStatic @Provides @IntoSet - @StatusBarScope + @CentralSurfacesScope fun bindStartable( manager: NotifPanelEventSourceManager, notifPanelController: NotificationPanelViewController - ): StatusBarComponent.Startable = + ): CentralSurfacesComponent.Startable = EventSourceStatusBarStartableImpl(manager, notifPanelController) } /** - * Management layer that bridges [SysUiSingleton] and [StatusBarScope]. Necessary because code that - * wants to listen to [NotifPanelEventSource] lives in [SysUiSingleton], but the events themselves - * come from [NotificationPanelViewController] in [StatusBarScope]. + * Management layer that bridges [SysUiSingleton] and [CentralSurfacesScope]. Necessary because code + * that wants to listen to [NotifPanelEventSource] lives in [SysUiSingleton], but the events + * themselves come from [NotificationPanelViewController] in [CentralSurfacesScope]. */ interface NotifPanelEventSourceManager : NotifPanelEventSource { var eventSource: NotifPanelEventSource? @@ -116,7 +116,7 @@ private class NotifPanelEventSourceManagerImpl private class EventSourceStatusBarStartableImpl( private val manager: NotifPanelEventSourceManager, private val notifPanelController: NotificationPanelViewController -) : StatusBarComponent.Startable { +) : CentralSurfacesComponent.Startable { override fun start() { manager.eventSource = notifPanelController diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index e3ebef99f45f..51bbf1c80478 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -38,7 +38,6 @@ import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.notification.AssistantFeedbackController; -import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger; @@ -87,7 +86,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationSectionsMan import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.leak.LeakDetector; import com.android.systemui.wmshell.BubblesManager; @@ -95,6 +94,8 @@ import com.android.systemui.wmshell.BubblesManager; import java.util.Optional; import java.util.concurrent.Executor; +import javax.inject.Provider; + import dagger.Binds; import dagger.Lazy; import dagger.Module; @@ -128,7 +129,6 @@ public interface NotificationsModule { Lazy<NotificationRowBinder> notificationRowBinderLazy, Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy, LeakDetector leakDetector, - ForegroundServiceDismissalFeatureController fgsFeatureController, IStatusBarService statusBarService, NotifLiveDataStoreImpl notifLiveDataStore, DumpManager dumpManager) { @@ -139,7 +139,6 @@ public interface NotificationsModule { notificationRowBinderLazy, notificationRemoteInputManagerLazy, leakDetector, - fgsFeatureController, statusBarService, notifLiveDataStore, dumpManager); @@ -150,7 +149,7 @@ public interface NotificationsModule { @Provides static NotificationGutsManager provideNotificationGutsManager( Context context, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, @Main Handler mainHandler, @Background Handler bgHandler, AccessibilityManager accessibilityManager, @@ -170,7 +169,7 @@ public interface NotificationsModule { DumpManager dumpManager) { return new NotificationGutsManager( context, - statusBarOptionalLazy, + centralSurfacesOptionalLazy, mainHandler, bgHandler, accessibilityManager, @@ -279,8 +278,8 @@ public interface NotificationsModule { @Provides static NotificationsController provideNotificationsController( Context context, - Lazy<NotificationsControllerImpl> realController, - Lazy<NotificationsControllerStub> stubController) { + Provider<NotificationsControllerImpl> realController, + Provider<NotificationsControllerStub> stubController) { if (context.getResources().getBoolean(R.bool.config_renderNotifications)) { return realController.get(); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt index a59d4211e68a..18abfcaab0e0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt @@ -23,11 +23,8 @@ import com.android.systemui.statusbar.notification.NotificationActivityStarter import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl import com.android.systemui.statusbar.notification.collection.render.NotifStackController import com.android.systemui.statusbar.notification.stack.NotificationListContainer -import com.android.systemui.statusbar.phone.StatusBar -import com.android.wm.shell.bubbles.Bubbles import java.io.FileDescriptor import java.io.PrintWriter -import java.util.Optional /** * The master controller for all notifications-related work @@ -37,8 +34,6 @@ import java.util.Optional */ interface NotificationsController { fun initialize( - statusBar: StatusBar, - bubblesOptional: Optional<Bubbles>, presenter: NotificationPresenter, listContainer: NotificationListContainer, stackController: NotifStackController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt index 48f2dafedcbb..98f45fa070c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -44,7 +44,7 @@ import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinde import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer import com.android.systemui.statusbar.notification.stack.NotificationListContainer import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper -import com.android.systemui.statusbar.phone.StatusBar +import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.RemoteInputUriController @@ -64,6 +64,7 @@ import javax.inject.Inject */ @SysUISingleton class NotificationsControllerImpl @Inject constructor( + private val centralSurfaces: Lazy<CentralSurfaces>, private val notifPipelineFlags: NotifPipelineFlags, private val notificationListener: NotificationListener, private val entryManager: NotificationEntryManager, @@ -86,12 +87,11 @@ class NotificationsControllerImpl @Inject constructor( private val headsUpViewBinder: HeadsUpViewBinder, private val clickerBuilder: NotificationClicker.Builder, private val animatedImageNotificationManager: AnimatedImageNotificationManager, - private val peopleSpaceWidgetManager: PeopleSpaceWidgetManager + private val peopleSpaceWidgetManager: PeopleSpaceWidgetManager, + private val bubblesOptional: Optional<Bubbles>, ) : NotificationsController { override fun initialize( - statusBar: StatusBar, - bubblesOptional: Optional<Bubbles>, presenter: NotificationPresenter, listContainer: NotificationListContainer, stackController: NotifStackController, @@ -109,7 +109,7 @@ class NotificationsControllerImpl @Inject constructor( notificationRowBinder.setNotificationClicker( clickerBuilder.build( - Optional.of(statusBar), bubblesOptional, notificationActivityStarter)) + Optional.of(centralSurfaces.get()), bubblesOptional, notificationActivityStarter)) notificationRowBinder.setUpWithPresenter( presenter, listContainer, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt index 1c9af11b7816..66701d1e37f1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt @@ -24,11 +24,8 @@ import com.android.systemui.statusbar.notification.NotificationActivityStarter import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl import com.android.systemui.statusbar.notification.collection.render.NotifStackController import com.android.systemui.statusbar.notification.stack.NotificationListContainer -import com.android.systemui.statusbar.phone.StatusBar -import com.android.wm.shell.bubbles.Bubbles import java.io.FileDescriptor import java.io.PrintWriter -import java.util.Optional import javax.inject.Inject /** @@ -39,8 +36,6 @@ class NotificationsControllerStub @Inject constructor( ) : NotificationsController { override fun initialize( - statusBar: StatusBar, - bubblesOptional: Optional<Bubbles>, presenter: NotificationPresenter, listContainer: NotificationListContainer, stackController: NotifStackController, @@ -75,4 +70,4 @@ class NotificationsControllerStub @Inject constructor( pw.println("Notification handling disabled") pw.println() } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java index dc3941332f0b..9fbd5c39dedd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java @@ -468,7 +468,7 @@ public class NotificationLogger implements StateListener { } /** - * Called by StatusBar to notify the logger that the panel expansion has changed. + * Called by CentralSurfaces to notify the logger that the panel expansion has changed. * The panel may be showing any of the normal notification panel, the AOD, or the bouncer. * @param isExpanded True if the panel is expanded. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/DungeonRow.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/DungeonRow.kt deleted file mode 100644 index dbfa27f1f68e..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/DungeonRow.kt +++ /dev/null @@ -1,43 +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.systemui.statusbar.notification.row - -import android.content.Context -import android.util.AttributeSet -import android.widget.LinearLayout -import android.widget.TextView -import com.android.systemui.R -import com.android.systemui.statusbar.StatusBarIconView -import com.android.systemui.statusbar.notification.collection.NotificationEntry - -class DungeonRow(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { - var entry: NotificationEntry? = null - set(value) { - field = value - update() - } - - private fun update() { - (findViewById(R.id.app_name) as TextView).apply { - text = entry?.row?.appName - } - - (findViewById(R.id.icon) as StatusBarIconView).apply { - set(entry?.icons?.statusBarIcon?.statusBarIcon) - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 1f7d93012e39..c237e1deeae3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -112,7 +112,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationChildrenCon import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.SwipeableView; import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.InflatedSmartReplyState; import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent; @@ -388,7 +388,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } return false; } else { - PackageManager packageManager = StatusBar.getPackageManagerForUser( + PackageManager packageManager = CentralSurfaces.getPackageManagerForUser( context, sbn.getUser().getIdentifier()); Boolean isSystemNotification = null; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ForegroundServiceDungeonView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ForegroundServiceDungeonView.kt deleted file mode 100644 index 17396ad31ba2..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ForegroundServiceDungeonView.kt +++ /dev/null @@ -1,38 +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.systemui.statusbar.notification.row - -import android.content.Context -import android.util.AttributeSet -import android.view.View - -import com.android.systemui.R - -class ForegroundServiceDungeonView(context: Context, attrs: AttributeSet) - : StackScrollerDecorView(context, attrs) { - override fun findContentView(): View? { - return findViewById(R.id.foreground_service_dungeon) - } - - override fun findSecondaryView(): View? { - return null - } - - override fun setVisible(visible: Boolean, animate: Boolean) { - // Visibility is controlled by the ForegroundServiceSectionController - } -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java index 1530e5238c67..4c693045bc88 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java @@ -47,7 +47,7 @@ import com.android.systemui.statusbar.notification.ConversationNotificationProce import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.policy.InflatedSmartReplyState; import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder; import com.android.systemui.statusbar.policy.SmartReplyStateInflater; @@ -841,7 +841,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder StatusBarNotification sbn = mEntry.getSbn(); final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()); - Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e); + Log.e(CentralSurfaces.TAG, "couldn't inflate view for notification " + ident, e); if (mCallback != null) { mCallback.handleInflationException(mRow.getEntry(), new InflationException("Couldn't inflate contentViews" + e)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 6d13024e5489..ebe6f03c44e1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -70,8 +70,8 @@ import com.android.systemui.statusbar.notification.collection.render.NotifGutsVi import com.android.systemui.statusbar.notification.dagger.NotificationsModule; import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.wmshell.BubblesManager; @@ -120,7 +120,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx @VisibleForTesting protected String mKeyToRemoveOnGutsClosed; - private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; + private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; private final Handler mMainHandler; private final Handler mBgHandler; private final Optional<BubblesManager> mBubblesManagerOptional; @@ -139,7 +139,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx * Injected constructor. See {@link NotificationsModule}. */ public NotificationGutsManager(Context context, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, @Main Handler mainHandler, @Background Handler bgHandler, AccessibilityManager accessibilityManager, @@ -158,7 +158,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx ShadeController shadeController, DumpManager dumpManager) { mContext = context; - mStatusBarOptionalLazy = statusBarOptionalLazy; + mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mMainHandler = mainHandler; mBgHandler = bgHandler; mAccessibilityManager = accessibilityManager; @@ -342,7 +342,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx } StatusBarNotification sbn = row.getEntry().getSbn(); UserHandle userHandle = sbn.getUser(); - PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext, + PackageManager pmUser = CentralSurfaces.getPackageManagerForUser(mContext, userHandle.getIdentifier()); feedbackInfo.bindGuts(pmUser, sbn, row.getEntry(), row, mAssistantFeedbackController); @@ -363,7 +363,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx // Settings link is only valid for notifications that specify a non-system user NotificationInfo.OnSettingsClickListener onSettingsClick = null; UserHandle userHandle = sbn.getUser(); - PackageManager pmUser = StatusBar.getPackageManagerForUser( + PackageManager pmUser = CentralSurfaces.getPackageManagerForUser( mContext, userHandle.getIdentifier()); final NotificationInfo.OnAppSettingsClickListener onAppSettingsClick = (View v, Intent intent) -> { @@ -416,7 +416,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx // Settings link is only valid for notifications that specify a non-system user NotificationInfo.OnSettingsClickListener onSettingsClick = null; UserHandle userHandle = sbn.getUser(); - PackageManager pmUser = StatusBar.getPackageManagerForUser( + PackageManager pmUser = CentralSurfaces.getPackageManagerForUser( mContext, userHandle.getIdentifier()); if (!userHandle.equals(UserHandle.ALL) @@ -458,7 +458,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx // Settings link is only valid for notifications that specify a non-system user NotificationConversationInfo.OnSettingsClickListener onSettingsClick = null; UserHandle userHandle = sbn.getUser(); - PackageManager pmUser = StatusBar.getPackageManagerForUser( + PackageManager pmUser = CentralSurfaces.getPackageManagerForUser( mContext, userHandle.getIdentifier()); final NotificationConversationInfo.OnAppSettingsClickListener onAppSettingsClick = (View v, Intent intent) -> { @@ -571,11 +571,12 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx .setLeaveOpenOnKeyguardHide(true); } - Optional<StatusBar> statusBarOptional = mStatusBarOptionalLazy.get(); - if (statusBarOptional.isPresent()) { + Optional<CentralSurfaces> centralSurfacesOptional = + mCentralSurfacesOptionalLazy.get(); + if (centralSurfacesOptional.isPresent()) { Runnable r = () -> mMainHandler.post( () -> openGutsInternal(view, x, y, menuItem)); - statusBarOptional.get().executeRunnableDismissingKeyguard( + centralSurfacesOptional.get().executeRunnableDismissingKeyguard( r, null /* cancelAction */, false /* dismissShade */, @@ -584,7 +585,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx return true; } /** - * When {@link StatusBar} doesn't exist, falling through to call + * When {@link CentralSurfaces} doesn't exist, falling through to call * {@link #openGutsInternal(View,int,int,NotificationMenuRowPlugin.MenuItem)}. */ } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java index a12d0073ef57..1a7417a78186 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java @@ -26,7 +26,7 @@ import com.android.systemui.statusbar.notification.row.ActivatableNotificationVi import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import dagger.Binds; import dagger.BindsInstance; @@ -100,7 +100,7 @@ public interface ExpandableNotificationRowComponent { // but since this field is used in the guts, it must be accurate. // Therefore we will only show the application label, or, failing that, the // package name. No substitutions. - PackageManager pmUser = StatusBar.getPackageManagerForUser( + PackageManager pmUser = CentralSurfaces.getPackageManagerForUser( context, statusBarNotification.getUser().getIdentifier()); final String pkg = statusBarNotification.getPackageName(); try { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationRowScope.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationRowScope.java index 4555b839a3f2..fa14123df11f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationRowScope.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationRowScope.java @@ -24,7 +24,7 @@ import java.lang.annotation.Retention; import javax.inject.Scope; /** - * Scope annotation for singleton items within the StatusBarComponent. + * Scope annotation for singleton items within the CentralSurfacesComponent. */ @Documented @Retention(RUNTIME) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ForegroundServiceSectionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ForegroundServiceSectionController.kt deleted file mode 100644 index 75ca3377fa89..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ForegroundServiceSectionController.kt +++ /dev/null @@ -1,168 +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.systemui.statusbar.notification.stack - -import android.content.Context -import android.service.notification.NotificationListenerService.REASON_CANCEL -import android.service.notification.NotificationListenerService.REASON_CANCEL_ALL -import android.service.notification.NotificationListenerService.REASON_CLICK -import android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED -import android.view.LayoutInflater -import android.view.View -import android.widget.LinearLayout -import com.android.systemui.R -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController -import com.android.systemui.statusbar.notification.NotificationEntryListener -import com.android.systemui.statusbar.notification.NotificationEntryManager -import com.android.systemui.statusbar.notification.collection.NotificationEntry -import com.android.systemui.statusbar.notification.row.DungeonRow -import com.android.systemui.util.Assert -import javax.inject.Inject - -/** - * Controller for the bottom area of NotificationStackScrollLayout. It owns swiped-away foreground - * service notifications and can reinstantiate them when requested. - */ -@SysUISingleton -class ForegroundServiceSectionController @Inject constructor( - val entryManager: NotificationEntryManager, - val featureController: ForegroundServiceDismissalFeatureController -) { - private val TAG = "FgsSectionController" - private var context: Context? = null - - private val entries = mutableSetOf<NotificationEntry>() - - private var entriesView: View? = null - - init { - if (featureController.isForegroundServiceDismissalEnabled()) { - entryManager.addNotificationRemoveInterceptor(this::shouldInterceptRemoval) - - entryManager.addNotificationEntryListener(object : NotificationEntryListener { - override fun onPostEntryUpdated(entry: NotificationEntry) { - if (entries.contains(entry)) { - removeEntry(entry) - addEntry(entry) - update() - } - } - }) - } - } - - private fun shouldInterceptRemoval( - key: String, - entry: NotificationEntry?, - reason: Int - ): Boolean { - Assert.isMainThread() - val isClearAll = reason == REASON_CANCEL_ALL - val isUserDismiss = reason == REASON_CANCEL || reason == REASON_CLICK - // REASON_APP_CANCEL and REASON_APP_CANCEL_ALL are ignored, because the - // foreground service associated with it is gone. - val isSummaryCancel = reason == REASON_GROUP_SUMMARY_CANCELED - - if (entry == null) return false - - // We only want to retain notifications that the user dismissed - // TODO: centralize the entry.isClearable logic and this so that it's clear when a notif is - // clearable - if (isUserDismiss && !entry.sbn.isClearable) { - if (!hasEntry(entry)) { - addEntry(entry) - update() - } - // TODO: This isn't ideal. Slightly better would at least be to have NEM update the - // notif list when an entry gets intercepted - entryManager.updateNotifications( - "FgsSectionController.onNotificationRemoveRequested") - return true - } else if ((isClearAll || isSummaryCancel) && !entry.sbn.isClearable) { - // In the case where a FGS notification is part of a group that is cleared or a clear - // all, we actually want to stop its removal but also not put it into the dungeon - return true - } else if (hasEntry(entry)) { - removeEntry(entry) - update() - return false - } - - return false - } - - private fun removeEntry(entry: NotificationEntry) { - Assert.isMainThread() - entries.remove(entry) - } - - private fun addEntry(entry: NotificationEntry) { - Assert.isMainThread() - entries.add(entry) - } - - fun hasEntry(entry: NotificationEntry): Boolean { - Assert.isMainThread() - return entries.contains(entry) - } - - fun initialize(context: Context) { - this.context = context - } - - fun createView(li: LayoutInflater): View { - entriesView = li.inflate(R.layout.foreground_service_dungeon, null) - // Start out gone - entriesView!!.visibility = View.GONE - return entriesView!! - } - - private fun update() { - Assert.isMainThread() - if (entriesView == null) { - throw IllegalStateException("ForegroundServiceSectionController is trying to show " + - "dismissed fgs notifications without having been initialized!") - } - - // TODO: these views should be recycled and not inflating on the main thread - (entriesView!!.findViewById(R.id.entry_list) as LinearLayout).apply { - removeAllViews() - entries.sortedBy { it.ranking.rank }.forEach { entry -> - val child = LayoutInflater.from(context) - .inflate(R.layout.foreground_service_dungeon_row, null) as DungeonRow - - child.entry = entry - child.setOnClickListener { - removeEntry(child.entry!!) - update() - entry.row.unDismiss() - entry.row.resetTranslation() - entryManager.updateNotifications("ForegroundServiceSectionController.onClick") - } - - addView(child) - } - } - - if (entries.isEmpty()) { - entriesView?.visibility = View.GONE - } else { - entriesView?.visibility = View.VISIBLE - } - } -} 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 2c4db7745fd4..efe559a64cc4 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 @@ -100,13 +100,12 @@ import com.android.systemui.statusbar.notification.row.ActivatableNotificationVi import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.row.FooterView; -import com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView; import com.android.systemui.statusbar.notification.row.StackScrollerDecorView; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; import com.android.systemui.statusbar.phone.HeadsUpTouchHelper; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.HeadsUpUtil; import com.android.systemui.statusbar.policy.ScrollAdapter; import com.android.systemui.util.Assert; @@ -309,7 +308,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } }; private NotificationStackScrollLogger mLogger; - private StatusBar mStatusBar; + private CentralSurfaces mCentralSurfaces; private int[] mTempInt2 = new int[2]; private boolean mGenerateChildOrderChangedEvent; private HashSet<Runnable> mAnimationFinishedRunnables = new HashSet<>(); @@ -453,7 +452,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private Interpolator mHideXInterpolator = Interpolators.FAST_OUT_SLOW_IN; private final NotificationSectionsManager mSectionsManager; - private ForegroundServiceDungeonView mFgsSectionView; private boolean mAnimateBottomOnLayout; private float mLastSentAppear; private float mLastSentExpandedHeight; @@ -614,14 +612,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } - void initializeForegroundServiceSection(ForegroundServiceDungeonView fgsSectionView) { - if (mFgsSectionView != null) { - return; - } - mFgsSectionView = fgsSectionView; - addView(mFgsSectionView, -1); - } - /** * Set the overexpansion of the panel to be applied to the view. */ @@ -3969,7 +3959,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mAmbientState.setExpansionChanging(false); if (!mIsExpanded) { resetScrollPosition(); - mStatusBar.resetUserExpandedStates(); + mCentralSurfaces.resetUserExpandedStates(); clearTemporaryViews(); clearUserLockedViews(); if (mSwipeHelper.isSwiping()) { @@ -4601,8 +4591,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setStatusBar(StatusBar statusBar) { - this.mStatusBar = statusBar; + public void setCentralSurfaces(CentralSurfaces centralSurfaces) { + this.mCentralSurfaces = centralSurfaces; } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) @@ -5270,7 +5260,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable Intent intent = showHistory ? new Intent(Settings.ACTION_NOTIFICATION_HISTORY) : new Intent(Settings.ACTION_NOTIFICATION_SETTINGS); - mStatusBar.startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP); + mCentralSurfaces.startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP); }); setEmptyShadeView(view); } @@ -5286,9 +5276,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable // incremented in the following "changeViewPosition" calls so that its value is correct for // subsequent calls. int offsetFromEnd = 1; - if (mFgsSectionView != null) { - changeViewPosition(mFgsSectionView, getChildCount() - offsetFromEnd++); - } changeViewPosition(mFooterView, getChildCount() - offsetFromEnd++); changeViewPosition(mEmptyShadeView, getChildCount() - offsetFromEnd++); 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 d1c63e3ade70..df6b8f59fc36 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 @@ -86,7 +86,6 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.ExpandAnimationParameters; -import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationEntryListener; @@ -109,7 +108,6 @@ import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; -import com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView; import com.android.systemui.statusbar.notification.row.NotificationGuts; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationSnooze; @@ -119,8 +117,8 @@ import com.android.systemui.statusbar.phone.HeadsUpTouchHelper; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; +import com.android.systemui.statusbar.phone.CentralSurfaces; +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -143,7 +141,7 @@ import kotlin.Unit; /** * Controller for {@link NotificationStackScrollLayout}. */ -@StatusBarComponent.StatusBarScope +@CentralSurfacesComponent.CentralSurfacesScope public class NotificationStackScrollLayoutController { private static final String TAG = "StackScrollerController"; private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG); @@ -170,8 +168,6 @@ public class NotificationStackScrollLayoutController { private final NotificationEntryManager mNotificationEntryManager; private final IStatusBarService mIStatusBarService; private final UiEventLogger mUiEventLogger; - private final ForegroundServiceDismissalFeatureController mFgFeatureController; - private final ForegroundServiceSectionController mFgServicesSectionController; private final LayoutInflater mLayoutInflater; private final NotificationRemoteInputManager mRemoteInputManager; private final VisualStabilityManager mVisualStabilityManager; @@ -180,8 +176,8 @@ public class NotificationStackScrollLayoutController { private final SysuiStatusBarStateController mStatusBarStateController; private final KeyguardBypassController mKeyguardBypassController; private final NotificationLockscreenUserManager mLockscreenUserManager; - // TODO: StatusBar should be encapsulated behind a Controller - private final StatusBar mStatusBar; + // TODO: CentralSurfaces should be encapsulated behind a Controller + private final CentralSurfaces mCentralSurfaces; private final SectionHeaderController mSilentHeaderController; private final LockscreenShadeTransitionController mLockscreenShadeTransitionController; private final InteractionJankMonitor mJankMonitor; @@ -334,7 +330,7 @@ public class NotificationStackScrollLayoutController { mView.updateSensitiveness(mStatusBarStateController.goingToFullShade(), mLockscreenUserManager.isAnyProfilePublicMode()); mView.onStatePostChange(mStatusBarStateController.fromShadeLocked()); - mNotificationEntryManager.updateNotifications("StatusBar state changed"); + mNotificationEntryManager.updateNotifications("CentralSurfaces state changed"); } }; @@ -435,7 +431,7 @@ public class NotificationStackScrollLayoutController { @Override public void onSnooze(StatusBarNotification sbn, NotificationSwipeActionHelper.SnoozeOption snoozeOption) { - mStatusBar.setNotificationSnoozed(sbn, snoozeOption); + mCentralSurfaces.setNotificationSnoozed(sbn, snoozeOption); } @Override @@ -488,7 +484,7 @@ public class NotificationStackScrollLayoutController { mView.addSwipedOutView(view); mFalsingCollector.onNotificationDismissed(); if (mFalsingCollector.shouldEnforceBouncer()) { - mStatusBar.executeRunnableDismissingKeyguard( + mCentralSurfaces.executeRunnableDismissingKeyguard( null, null /* cancelAction */, false /* dismissShade */, @@ -561,7 +557,7 @@ public class NotificationStackScrollLayoutController { @Override public float getFalsingThresholdFactor() { - return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f; + return mCentralSurfaces.isWakeUpComingFromTouch() ? 1.5f : 1.0f; } @Override @@ -648,7 +644,7 @@ public class NotificationStackScrollLayoutController { FalsingManager falsingManager, @Main Resources resources, NotificationSwipeHelper.Builder notificationSwipeHelperBuilder, - StatusBar statusBar, + CentralSurfaces centralSurfaces, ScrimController scrimController, NotificationGroupManagerLegacy legacyGroupManager, GroupExpansionManager groupManager, @@ -660,8 +656,6 @@ public class NotificationStackScrollLayoutController { LockscreenShadeTransitionController lockscreenShadeTransitionController, IStatusBarService iStatusBarService, UiEventLogger uiEventLogger, - ForegroundServiceDismissalFeatureController fgFeatureController, - ForegroundServiceSectionController fgServicesSectionController, LayoutInflater layoutInflater, NotificationRemoteInputManager remoteInputManager, VisualStabilityManager visualStabilityManager, @@ -691,7 +685,7 @@ public class NotificationStackScrollLayoutController { mFalsingManager = falsingManager; mResources = resources; mNotificationSwipeHelperBuilder = notificationSwipeHelperBuilder; - mStatusBar = statusBar; + mCentralSurfaces = centralSurfaces; mScrimController = scrimController; mJankMonitor = jankMonitor; groupManager.registerGroupExpansionChangeListener( @@ -699,7 +693,7 @@ public class NotificationStackScrollLayoutController { legacyGroupManager.registerGroupChangeListener(new OnGroupChangeListener() { @Override public void onGroupsChanged() { - mStatusBar.requestNotificationUpdate("onGroupsChanged"); + mCentralSurfaces.requestNotificationUpdate("onGroupsChanged"); } }); mNotifPipelineFlags = notifPipelineFlags; @@ -709,8 +703,6 @@ public class NotificationStackScrollLayoutController { mNotificationEntryManager = notificationEntryManager; mIStatusBarService = iStatusBarService; mUiEventLogger = uiEventLogger; - mFgFeatureController = fgFeatureController; - mFgServicesSectionController = fgServicesSectionController; mLayoutInflater = layoutInflater; mRemoteInputManager = remoteInputManager; mVisualStabilityManager = visualStabilityManager; @@ -724,7 +716,7 @@ public class NotificationStackScrollLayoutController { mView.setController(this); mView.setLogger(mLogger); mView.setTouchHandler(new TouchHandler()); - mView.setStatusBar(mStatusBar); + mView.setCentralSurfaces(mCentralSurfaces); mView.setClearAllAnimationListener(this::onAnimationEnd); mView.setClearAllListener((selection) -> mUiEventLogger.log( NotificationPanelEvent.fromSelection(selection))); @@ -744,12 +736,6 @@ public class NotificationStackScrollLayoutController { mNotificationRoundnessManager.setShouldRoundPulsingViews( !mKeyguardBypassController.getBypassEnabled()); - if (mFgFeatureController.isForegroundServiceDismissalEnabled()) { - mView.initializeForegroundServiceSection( - (ForegroundServiceDungeonView) mFgServicesSectionController.createView( - mLayoutInflater)); - } - mSwipeHelper = mNotificationSwipeHelperBuilder .setSwipeDirection(SwipeHelper.X) .setNotificationCallback(mNotificationCallback) @@ -1420,7 +1406,7 @@ public class NotificationStackScrollLayoutController { return mNotificationRoundnessManager; } - public NotificationListContainer getNotificationListContainer() { + NotificationListContainer getNotificationListContainer() { return mNotificationListContainer; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutListContainerModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutListContainerModule.java new file mode 100644 index 000000000000..3dcaae28e181 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutListContainerModule.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.stack; + +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; + +import dagger.Module; +import dagger.Provides; + +@Module +public abstract class NotificationStackScrollLayoutListContainerModule { + @Provides + @CentralSurfacesComponent.CentralSurfacesScope + static NotificationListContainer provideListContainer( + NotificationStackScrollLayoutController nsslController) { + return nsslController.getNotificationListContainer(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index d5d1ceada88a..fe637c14ee33 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -717,7 +717,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp public void run() { mNotificationShadeWindowController.setForceDozeBrightness(false); } - }, StatusBar.FADE_KEYGUARD_DURATION_PULSING); + }, CentralSurfaces.FADE_KEYGUARD_DURATION_PULSING); } public void finishKeyguardFadingAway() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index 95e08eab6064..5642744d3390 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -222,7 +222,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule; import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; @@ -260,8 +260,20 @@ import javax.inject.Named; import dagger.Lazy; -/** */ -public class StatusBar extends CoreStartable implements +/** + * A class handling initialization and coordination between some of the key central surfaces in + * System UI: The notification shade, the keyguard (lockscreen), and the status bar. + * + * This class is not our ideal architecture because it doesn't enforce much isolation between these + * three mostly disparate surfaces. In an ideal world, this class would not exist. Instead, we would + * break it up into three modules -- one for each of those three surfaces -- and we would define any + * APIs that are needed for these surfaces to communicate with each other when necessary. + * + * <b>If at all possible, please avoid adding additional code to this monstrous class! Our goal is + * to break up this class into many small classes, and any code added here will slow down that goal. + * </b> + */ +public class CentralSurfaces extends CoreStartable implements ActivityStarter, LifecycleOwner { public static final boolean MULTIUSER_DEBUG = false; @@ -278,7 +290,7 @@ public class StatusBar extends CoreStartable implements "com.android.systemui.statusbar.banner_action_cancel"; private static final String BANNER_ACTION_SETUP = "com.android.systemui.statusbar.banner_action_setup"; - public static final String TAG = "StatusBar"; + public static final String TAG = "CentralSurfaces"; public static final boolean DEBUG = false; public static final boolean SPEW = false; public static final boolean DUMPTRUCK = true; // extra dumpsys info @@ -343,8 +355,9 @@ public class StatusBar extends CoreStartable implements private final LockscreenShadeTransitionController mLockscreenShadeTransitionController; private final DreamOverlayStateController mDreamOverlayStateController; - private StatusBarCommandQueueCallbacks mCommandQueueCallbacks; + private CentralSurfacesCommandQueueCallbacks mCommandQueueCallbacks; private float mTransitionToFullShadeProgress = 0f; + private NotificationListContainer mNotifListContainer; void onStatusBarWindowStateChanged(@WindowVisibleState int state) { updateBubblesVisibility(); @@ -468,7 +481,7 @@ public class StatusBar extends CoreStartable implements private PhoneStatusBarTransitions mStatusBarTransitions; private AuthRippleController mAuthRippleController; @WindowVisibleState private int mStatusBarWindowState = WINDOW_STATE_SHOWING; - protected NotificationShadeWindowController mNotificationShadeWindowController; + protected final NotificationShadeWindowController mNotificationShadeWindowController; private final StatusBarWindowController mStatusBarWindowController; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @VisibleForTesting @@ -494,10 +507,8 @@ public class StatusBar extends CoreStartable implements protected NotificationShadeWindowViewController mNotificationShadeWindowViewController; private final DozeParameters mDozeParameters; private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; - private final StatusBarComponent.Factory mStatusBarComponentFactory; + private final CentralSurfacesComponent.Factory mCentralSurfacesComponentFactory; private final PluginManager mPluginManager; - private final StatusBarNotificationActivityStarter.Builder - mStatusBarNotificationActivityStarterBuilder; private final ShadeController mShadeController; private final InitController mInitController; @@ -543,7 +554,7 @@ public class StatusBar extends CoreStartable implements private final MessageRouter mMessageRouter; private final WallpaperManager mWallpaperManager; - private StatusBarComponent mStatusBarComponent; + private CentralSurfacesComponent mCentralSurfacesComponent; // Flags for disabling the status bar // Two variables becaseu the first one evidently ran out of room for new flags. @@ -665,7 +676,7 @@ public class StatusBar extends CoreStartable implements private final ActivityLaunchAnimator mActivityLaunchAnimator; private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider; - protected StatusBarNotificationPresenter mPresenter; + protected NotificationPresenter mPresenter; private NotificationActivityStarter mNotificationActivityStarter; private final Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy; private final Optional<BubblesManager> mBubblesManagerOptional; @@ -684,13 +695,13 @@ public class StatusBar extends CoreStartable implements /** - * Public constructor for StatusBar. + * Public constructor for CentralSurfaces. * - * StatusBar is considered optional, and therefore can not be marked as @Inject directly. + * CentralSurfaces is considered optional, and therefore can not be marked as @Inject directly. * Instead, an @Provide method is included. See {@link StatusBarPhoneModule}. */ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") - public StatusBar( + public CentralSurfaces( Context context, NotificationsController notificationsController, FragmentService fragmentService, @@ -750,10 +761,8 @@ public class StatusBar extends CoreStartable implements DozeScrimController dozeScrimController, VolumeComponent volumeComponent, CommandQueue commandQueue, - StatusBarComponent.Factory statusBarComponentFactory, + CentralSurfacesComponent.Factory centralSurfacesComponentFactory, PluginManager pluginManager, - StatusBarNotificationActivityStarter.Builder - statusBarNotificationActivityStarterBuilder, ShadeController shadeController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, ViewMediatorCallback viewMediatorCallback, @@ -848,9 +857,8 @@ public class StatusBar extends CoreStartable implements mNotificationShadeDepthControllerLazy = notificationShadeDepthControllerLazy; mVolumeComponent = volumeComponent; mCommandQueue = commandQueue; - mStatusBarComponentFactory = statusBarComponentFactory; + mCentralSurfacesComponentFactory = centralSurfacesComponentFactory; mPluginManager = pluginManager; - mStatusBarNotificationActivityStarterBuilder = statusBarNotificationActivityStarterBuilder; mShadeController = shadeController; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mKeyguardViewMediatorCallback = viewMediatorCallback; @@ -879,7 +887,7 @@ public class StatusBar extends CoreStartable implements mLockscreenShadeTransitionController = lockscreenShadeTransitionController; mStartingSurfaceOptional = startingSurfaceOptional; mNotifPipelineFlags = notifPipelineFlags; - lockscreenShadeTransitionController.setStatusbar(this); + lockscreenShadeTransitionController.setCentralSurfaces(this); statusBarWindowStateController.addListener(this::onStatusBarWindowStateChanged); mScreenOffAnimationController = screenOffAnimationController; @@ -1111,7 +1119,7 @@ public class StatusBar extends CoreStartable implements } private void onFoldedStateChanged(boolean isFolded, boolean willGoToSleep) { - Trace.beginSection("StatusBar#onFoldedStateChanged"); + Trace.beginSection("CentralSurfaces#onFoldedStateChanged"); onFoldedStateChangedInternal(isFolded, willGoToSleep); Trace.endSection(); } @@ -1155,19 +1163,14 @@ public class StatusBar extends CoreStartable implements updateTheme(); inflateStatusBarWindow(); - mNotificationShadeWindowViewController.setService(this, mNotificationShadeWindowController); mNotificationShadeWindowView.setOnTouchListener(getStatusBarWindowTouchListener()); mWallpaperController.setRootView(mNotificationShadeWindowView); - // TODO: Deal with the ugliness that comes from having some of the statusbar broken out + // TODO: Deal with the ugliness that comes from having some of the status bar broken out // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot. - NotificationListContainer notifListContainer = - mStackScrollerController.getNotificationListContainer(); - mNotificationLogger.setUpWithContainer(notifListContainer); - + mNotificationLogger.setUpWithContainer(mNotifListContainer); mNotificationIconAreaController.setupShelf(mNotificationShelfController); mPanelExpansionStateManager.addExpansionListener(mWakeUpCoordinator); - mUserSwitcherController.init(mNotificationShadeWindowView); // Allow plugins to reference DarkIconDispatcher and StatusBarStateController @@ -1175,7 +1178,7 @@ public class StatusBar extends CoreStartable implements mPluginDependencyProvider.allowPluginDependency(StatusBarStateController.class); // Set up CollapsedStatusBarFragment and PhoneStatusBarView - StatusBarInitializer initializer = mStatusBarComponent.getStatusBarInitializer(); + StatusBarInitializer initializer = mCentralSurfacesComponent.getStatusBarInitializer(); initializer.setStatusBarViewUpdatedListener( (statusBarView, statusBarViewController, statusBarTransitions) -> { mStatusBarView = statusBarView; @@ -1192,7 +1195,7 @@ public class StatusBar extends CoreStartable implements setBouncerShowingForStatusBarComponents(mBouncerShowing); checkBarModes(); }); - initializer.initializeStatusBar(mStatusBarComponent); + initializer.initializeStatusBar(mCentralSurfacesComponent); mStatusBarTouchableRegionManager.setup(this, mNotificationShadeWindowView); mHeadsUpManager.addListener(mNotificationPanelViewController.getOnHeadsUpChangedListener()); @@ -1442,65 +1445,19 @@ public class StatusBar extends CoreStartable implements mActivityLaunchAnimator.addListener(mActivityLaunchAnimatorListener); mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider( mNotificationShadeWindowViewController, - mStackScrollerController.getNotificationListContainer(), - mHeadsUpManager, - mJankMonitor - ); - - // TODO: inject this. - mPresenter = new StatusBarNotificationPresenter( - mContext, - mNotificationPanelViewController, + mNotifListContainer, mHeadsUpManager, - mNotificationShadeWindowView, - mStackScrollerController, - mDozeScrimController, - mScrimController, - mNotificationShadeWindowController, - mDynamicPrivacyController, - mKeyguardStateController, - mKeyguardIndicationController, - this /* statusBar */, - mShadeController, - mLockscreenShadeTransitionController, - mCommandQueue, - mViewHierarchyManager, - mLockscreenUserManager, - mStatusBarStateController, - mNotifShadeEventSource, - mEntryManager, - mMediaManager, - mGutsManager, - mKeyguardUpdateMonitor, - mLockscreenGestureLogger, - mInitController, - mNotificationInterruptStateProvider, - mRemoteInputManager, - mConfigurationController, - mNotifPipelineFlags); - + mJankMonitor); mNotificationShelfController.setOnActivatedListener(mPresenter); mRemoteInputManager.addControllerCallback(mNotificationShadeWindowController); - - mNotificationActivityStarter = - mStatusBarNotificationActivityStarterBuilder - .setStatusBar(this) - .setActivityLaunchAnimator(mActivityLaunchAnimator) - .setNotificationAnimatorControllerProvider(mNotificationAnimationProvider) - .setNotificationPresenter(mPresenter) - .setNotificationPanelViewController(mNotificationPanelViewController) - .build(); mStackScrollerController.setNotificationActivityStarter(mNotificationActivityStarter); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); - mNotificationsController.initialize( - this, - mBubblesOptional, mPresenter, - mStackScrollerController.getNotificationListContainer(), + mNotifListContainer, mStackScrollerController.getNotifStackController(), mNotificationActivityStarter, - mPresenter); + mCentralSurfacesComponent.getBindRowCallback()); } /** @@ -1558,30 +1515,34 @@ public class StatusBar extends CoreStartable implements } private void inflateStatusBarWindow() { - if (mStatusBarComponent != null) { + if (mCentralSurfacesComponent != null) { // Tear down - for (StatusBarComponent.Startable startable : mStatusBarComponent.getStartables()) { - startable.stop(); + for (CentralSurfacesComponent.Startable s : mCentralSurfacesComponent.getStartables()) { + s.stop(); } } - mStatusBarComponent = mStatusBarComponentFactory.create(); - mFragmentService.addFragmentInstantiationProvider(mStatusBarComponent); + mCentralSurfacesComponent = mCentralSurfacesComponentFactory.create(); + mFragmentService.addFragmentInstantiationProvider(mCentralSurfacesComponent); - mNotificationShadeWindowView = mStatusBarComponent.getNotificationShadeWindowView(); - mNotificationShadeWindowViewController = mStatusBarComponent + mNotificationShadeWindowView = mCentralSurfacesComponent.getNotificationShadeWindowView(); + mNotificationShadeWindowViewController = mCentralSurfacesComponent .getNotificationShadeWindowViewController(); mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView); mNotificationShadeWindowViewController.setupExpandedStatusBar(); - mNotificationPanelViewController = mStatusBarComponent.getNotificationPanelViewController(); - mStatusBarComponent.getLockIconViewController().init(); - mStackScrollerController = mStatusBarComponent.getNotificationStackScrollLayoutController(); + mNotificationPanelViewController = + mCentralSurfacesComponent.getNotificationPanelViewController(); + mCentralSurfacesComponent.getLockIconViewController().init(); + mStackScrollerController = + mCentralSurfacesComponent.getNotificationStackScrollLayoutController(); mStackScroller = mStackScrollerController.getView(); - - mNotificationShelfController = mStatusBarComponent.getNotificationShelfController(); - mAuthRippleController = mStatusBarComponent.getAuthRippleController(); + mNotifListContainer = mCentralSurfacesComponent.getNotificationListContainer(); + mPresenter = mCentralSurfacesComponent.getNotificationPresenter(); + mNotificationActivityStarter = mCentralSurfacesComponent.getNotificationActivityStarter(); + mNotificationShelfController = mCentralSurfacesComponent.getNotificationShelfController(); + mAuthRippleController = mCentralSurfacesComponent.getAuthRippleController(); mAuthRippleController.init(); - mHeadsUpManager.addListener(mStatusBarComponent.getStatusBarHeadsUpChangeListener()); + mHeadsUpManager.addListener(mCentralSurfacesComponent.getStatusBarHeadsUpChangeListener()); // Listen for demo mode changes mDemoModeController.addCallback(mDemoModeCallback); @@ -1589,18 +1550,19 @@ public class StatusBar extends CoreStartable implements if (mCommandQueueCallbacks != null) { mCommandQueue.removeCallback(mCommandQueueCallbacks); } - mCommandQueueCallbacks = mStatusBarComponent.getStatusBarCommandQueueCallbacks(); + mCommandQueueCallbacks = + mCentralSurfacesComponent.getCentralSurfacesCommandQueueCallbacks(); // Connect in to the status bar manager service mCommandQueue.addCallback(mCommandQueueCallbacks); - // Perform all other initialization for StatusBarScope - for (StatusBarComponent.Startable startable : mStatusBarComponent.getStartables()) { - startable.start(); + // Perform all other initialization for CentralSurfacesScope + for (CentralSurfacesComponent.Startable s : mCentralSurfacesComponent.getStartables()) { + s.start(); } } protected void startKeyguard() { - Trace.beginSection("StatusBar#startKeyguard"); + Trace.beginSection("CentralSurfaces#startKeyguard"); mBiometricUnlockController = mBiometricUnlockControllerLazy.get(); mBiometricUnlockController.setBiometricModeListener( new BiometricUnlockController.BiometricModeListener() { @@ -1621,7 +1583,7 @@ public class StatusBar extends CoreStartable implements @Override public void notifyBiometricAuthModeChanged() { - StatusBar.this.notifyBiometricAuthModeChanged(); + CentralSurfaces.this.notifyBiometricAuthModeChanged(); } private void setWakeAndUnlocking(boolean wakeAndUnlocking) { @@ -1630,7 +1592,7 @@ public class StatusBar extends CoreStartable implements } } }); - mStatusBarKeyguardViewManager.registerStatusBar( + mStatusBarKeyguardViewManager.registerCentralSurfaces( /* statusBar= */ this, mNotificationPanelViewController, mPanelExpansionStateManager, @@ -1759,7 +1721,7 @@ public class StatusBar extends CoreStartable implements getDelegate().onIntentStarted(willAnimate); if (willAnimate) { - StatusBar.this.mIsLaunchingActivityOverLockscreen = true; + CentralSurfaces.this.mIsLaunchingActivityOverLockscreen = true; } } @@ -1769,7 +1731,7 @@ public class StatusBar extends CoreStartable implements // animation so that we can assume that mIsLaunchingActivityOverLockscreen // being true means that we will collapse the shade (or at least run the // post collapse runnables) later on. - StatusBar.this.mIsLaunchingActivityOverLockscreen = false; + CentralSurfaces.this.mIsLaunchingActivityOverLockscreen = false; getDelegate().onLaunchAnimationEnd(isExpandingFullyAbove); } @@ -1779,7 +1741,7 @@ public class StatusBar extends CoreStartable implements // animation so that we can assume that mIsLaunchingActivityOverLockscreen // being true means that we will collapse the shade (or at least run the // post collapse runnables) later on. - StatusBar.this.mIsLaunchingActivityOverLockscreen = false; + CentralSurfaces.this.mIsLaunchingActivityOverLockscreen = false; getDelegate().onLaunchAnimationCancelled(); } }; @@ -2603,7 +2565,7 @@ public class StatusBar extends CoreStartable implements // ordering. mMainExecutor.execute(mShadeController::runPostCollapseRunnables); } - } else if (StatusBar.this.isInLaunchTransition() + } else if (CentralSurfaces.this.isInLaunchTransition() && mNotificationPanelViewController.isLaunchTransitionFinished()) { // We are not dismissing the shade, but the launch transition is already @@ -2626,7 +2588,7 @@ public class StatusBar extends CoreStartable implements private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - Trace.beginSection("StatusBar#onReceive"); + Trace.beginSection("CentralSurfaces#onReceive"); if (DEBUG) Log.v(TAG, "onReceive: " + intent); String action = intent.getAction(); String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY); @@ -2772,7 +2734,9 @@ public class StatusBar extends CoreStartable implements void handleVisibleToUserChangedImpl(boolean visibleToUser) { if (visibleToUser) { /* The LEDs are turned off when the notification panel is shown, even just a little bit. - * See also StatusBar.setPanelExpanded for another place where we attempt to do this. */ + * See also CentralSurfaces.setPanelExpanded for another place where we attempt to do + * this. + */ boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp(); boolean clearNotificationEffects = !mPresenter.isPresenterFullyCollapsed() && @@ -2921,8 +2885,9 @@ public class StatusBar extends CoreStartable implements // turned off fully. boolean keyguardForDozing = mDozeServiceHost.getDozingRequested() && (!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard)); + boolean isWakingAndOccluded = isOccluded() && isWaking(); boolean shouldBeKeyguard = (mStatusBarStateController.isKeyguardRequested() - || keyguardForDozing) && !wakeAndUnlocking; + || keyguardForDozing) && !wakeAndUnlocking && !isWakingAndOccluded; if (keyguardForDozing) { updatePanelExpansionForKeyguard(); } @@ -2951,7 +2916,7 @@ public class StatusBar extends CoreStartable implements } public void showKeyguardImpl() { - Trace.beginSection("StatusBar#showKeyguard"); + Trace.beginSection("CentralSurfaces#showKeyguard"); mIsKeyguard = true; // In case we're locking while a smartspace transition is in progress, reset it. mKeyguardUnlockAnimationController.resetSmartspaceTransition(); @@ -3074,7 +3039,7 @@ public class StatusBar extends CoreStartable implements */ public boolean hideKeyguardImpl(boolean forceStateChange) { mIsKeyguard = false; - Trace.beginSection("StatusBar#hideKeyguard"); + Trace.beginSection("CentralSurfaces#hideKeyguard"); boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide(); int previousState = mStatusBarStateController.getState(); if (!(mStatusBarStateController.setState(StatusBarState.SHADE, forceStateChange))) { @@ -3191,7 +3156,7 @@ public class StatusBar extends CoreStartable implements private void updateDozingState() { Trace.traceCounter(Trace.TRACE_TAG_APP, "dozing", mDozing ? 1 : 0); - Trace.beginSection("StatusBar#updateDozingState"); + Trace.beginSection("CentralSurfaces#updateDozingState"); boolean visibleNotOccluded = mStatusBarKeyguardViewManager.isShowing() && !mStatusBarKeyguardViewManager.isOccluded(); @@ -3546,7 +3511,7 @@ public class StatusBar extends CoreStartable implements @Override public void onStartedGoingToSleep() { - String tag = "StatusBar#onStartedGoingToSleep"; + String tag = "CentralSurfaces#onStartedGoingToSleep"; DejankUtils.startDetectingBlockingIpcs(tag); updateRevealEffect(false /* wakingUp */); updateNotificationPanelTouchState(); @@ -3566,7 +3531,7 @@ public class StatusBar extends CoreStartable implements @Override public void onStartedWakingUp() { - String tag = "StatusBar#onStartedWakingUp"; + String tag = "CentralSurfaces#onStartedWakingUp"; DejankUtils.startDetectingBlockingIpcs(tag); mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> { mDeviceInteractive = true; @@ -3641,7 +3606,7 @@ public class StatusBar extends CoreStartable implements @Override public void onScreenTurnedOff() { - Trace.beginSection("StatusBar#onScreenTurnedOff"); + Trace.beginSection("CentralSurfaces#onScreenTurnedOff"); mFalsingCollector.onScreenOff(); mScrimController.onScreenTurnedOff(); if (mCloseQsBeforeScreenOff) { @@ -3732,6 +3697,10 @@ public class StatusBar extends CoreStartable implements == WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP; } + boolean isWaking() { + return mWakefulnessLifecycle.getWakefulness() == WakefulnessLifecycle.WAKEFULNESS_WAKING; + } + public void notifyBiometricAuthModeChanged() { mDozeServiceHost.updateDozing(); updateScrimController(); @@ -3748,7 +3717,7 @@ public class StatusBar extends CoreStartable implements @VisibleForTesting public void updateScrimController() { - Trace.beginSection("StatusBar#updateScrimController"); + Trace.beginSection("CentralSurfaces#updateScrimController"); boolean unlocking = mKeyguardStateController.isShowing() && ( mBiometricUnlockController.isWakeAndUnlock() @@ -4314,7 +4283,7 @@ public class StatusBar extends CoreStartable implements if (mBrightnessMirrorController != null) { mBrightnessMirrorController.onDensityOrFontScaleChanged(); } - // TODO: Bring these out of StatusBar. + // TODO: Bring these out of CentralSurfaces. mUserInfoControllerImpl.onDensityOrFontScaleChanged(); mUserSwitcherController.onDensityOrFontScaleChanged(); mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext); @@ -4372,7 +4341,7 @@ public class StatusBar extends CoreStartable implements mDozeServiceHost.updateDozing(); updateTheme(); mNavigationBarController.touchAutoDim(mDisplayId); - Trace.beginSection("StatusBar#updateKeyguardState"); + Trace.beginSection("CentralSurfaces#updateKeyguardState"); if (mState == StatusBarState.KEYGUARD) { mNotificationPanelViewController.cancelPendingPanelCollapse(); } @@ -4395,7 +4364,7 @@ public class StatusBar extends CoreStartable implements @Override public void onDozingChanged(boolean isDozing) { - Trace.beginSection("StatusBar#updateDozing"); + Trace.beginSection("CentralSurfaces#updateDozing"); mDozing = isDozing; // Collapse the notification panel if open diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java index aeb782660173..536be1c1a866 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java @@ -59,7 +59,7 @@ import com.android.systemui.statusbar.DisableFlagsLogger; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -70,9 +70,9 @@ import java.util.Optional; import javax.inject.Inject; /** */ -@StatusBarComponent.StatusBarScope -public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { - private final StatusBar mStatusBar; +@CentralSurfacesComponent.CentralSurfacesScope +public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callbacks { + private final CentralSurfaces mCentralSurfaces; private final Context mContext; private final ShadeController mShadeController; private final CommandQueue mCommandQueue; @@ -105,8 +105,8 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK); @Inject - StatusBarCommandQueueCallbacks( - StatusBar statusBar, + CentralSurfacesCommandQueueCallbacks( + CentralSurfaces centralSurfaces, Context context, @Main Resources resources, ShadeController shadeController, @@ -133,7 +133,7 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { DisableFlagsLogger disableFlagsLogger, @DisplayId int displayId) { - mStatusBar = statusBar; + mCentralSurfaces = centralSurfaces; mContext = context; mShadeController = shadeController; mCommandQueue = commandQueue; @@ -172,12 +172,12 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { if (!containsType(types, ITYPE_STATUS_BAR)) { return; } - mStatusBar.clearTransient(); + mCentralSurfaces.clearTransient(); } @Override public void addQsTile(ComponentName tile) { - QSPanelController qsPanelController = mStatusBar.getQSPanelController(); + QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController(); if (qsPanelController != null && qsPanelController.getHost() != null) { qsPanelController.getHost().addTile(tile); } @@ -185,7 +185,7 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { @Override public void remQsTile(ComponentName tile) { - QSPanelController qsPanelController = mStatusBar.getQSPanelController(); + QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController(); if (qsPanelController != null && qsPanelController.getHost() != null) { qsPanelController.getHost().removeTile(tile); } @@ -193,7 +193,7 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { @Override public void clickTile(ComponentName tile) { - QSPanelController qsPanelController = mStatusBar.getQSPanelController(); + QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController(); if (qsPanelController != null) { qsPanelController.clickTile(tile); } @@ -207,9 +207,9 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { @Override public void animateExpandNotificationsPanel() { - if (StatusBar.SPEW) { - Log.d(StatusBar.TAG, - "animateExpand: mExpandedVisible=" + mStatusBar.isExpandedVisible()); + if (CentralSurfaces.SPEW) { + Log.d(CentralSurfaces.TAG, + "animateExpand: mExpandedVisible=" + mCentralSurfaces.isExpandedVisible()); } if (!mCommandQueue.panelsEnabled()) { return; @@ -220,9 +220,9 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { @Override public void animateExpandSettingsPanel(@Nullable String subPanel) { - if (StatusBar.SPEW) { - Log.d(StatusBar.TAG, - "animateExpand: mExpandedVisible=" + mStatusBar.isExpandedVisible()); + if (CentralSurfaces.SPEW) { + Log.d(CentralSurfaces.TAG, + "animateExpand: mExpandedVisible=" + mCentralSurfaces.isExpandedVisible()); } if (!mCommandQueue.panelsEnabled()) { return; @@ -244,7 +244,7 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { @Override public void dismissKeyboardShortcutsMenu() { - mStatusBar.resendMessage(StatusBar.MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU); + mCentralSurfaces.resendMessage(CentralSurfaces.MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU); } /** * State is one or more of the DISABLE constants from StatusBarManager. @@ -257,22 +257,22 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { int state2BeforeAdjustment = state2; state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2); - Log.d(StatusBar.TAG, + Log.d(CentralSurfaces.TAG, mDisableFlagsLogger.getDisableFlagsString( /* old= */ new DisableFlagsLogger.DisableState( - mStatusBar.getDisabled1(), mStatusBar.getDisabled2()), + mCentralSurfaces.getDisabled1(), mCentralSurfaces.getDisabled2()), /* new= */ new DisableFlagsLogger.DisableState( state1, state2BeforeAdjustment), /* newStateAfterLocalModification= */ new DisableFlagsLogger.DisableState( state1, state2))); - final int old1 = mStatusBar.getDisabled1(); + final int old1 = mCentralSurfaces.getDisabled1(); final int diff1 = state1 ^ old1; - mStatusBar.setDisabled1(state1); + mCentralSurfaces.setDisabled1(state1); - final int old2 = mStatusBar.getDisabled2(); + final int old2 = mCentralSurfaces.getDisabled2(); final int diff2 = state2 ^ old2; - mStatusBar.setDisabled2(state2); + mCentralSurfaces.setDisabled2(state2); if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) { if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) { @@ -281,17 +281,17 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { } if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) { - if (mStatusBar.areNotificationAlertsDisabled()) { + if (mCentralSurfaces.areNotificationAlertsDisabled()) { mHeadsUpManager.releaseAllImmediately(); } } if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) { - mStatusBar.updateQsExpansionEnabled(); + mCentralSurfaces.updateQsExpansionEnabled(); } if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) { - mStatusBar.updateQsExpansionEnabled(); + mCentralSurfaces.updateQsExpansionEnabled(); if ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) { mShadeController.animateCollapsePanels(); } @@ -304,8 +304,8 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { */ @Override public void handleSystemKey(int key) { - if (StatusBar.SPEW) { - Log.d(StatusBar.TAG, "handleNavigationKey: " + key); + if (CentralSurfaces.SPEW) { + Log.d(CentralSurfaces.TAG, "handleNavigationKey: " + key); } if (!mCommandQueue.panelsEnabled() || !mKeyguardUpdateMonitor.isDeviceInteractive() || mKeyguardStateController.isShowing() && !mKeyguardStateController.isOccluded()) { @@ -341,81 +341,82 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { @Override public void onCameraLaunchGestureDetected(int source) { - mStatusBar.setLastCameraLaunchSource(source); - if (mStatusBar.isGoingToSleep()) { - if (StatusBar.DEBUG_CAMERA_LIFT) { - Slog.d(StatusBar.TAG, "Finish going to sleep before launching camera"); + mCentralSurfaces.setLastCameraLaunchSource(source); + if (mCentralSurfaces.isGoingToSleep()) { + if (CentralSurfaces.DEBUG_CAMERA_LIFT) { + Slog.d(CentralSurfaces.TAG, "Finish going to sleep before launching camera"); } - mStatusBar.setLaunchCameraOnFinishedGoingToSleep(true); + mCentralSurfaces.setLaunchCameraOnFinishedGoingToSleep(true); return; } if (!mNotificationPanelViewController.canCameraGestureBeLaunched()) { - if (StatusBar.DEBUG_CAMERA_LIFT) { - Slog.d(StatusBar.TAG, "Can't launch camera right now"); + if (CentralSurfaces.DEBUG_CAMERA_LIFT) { + Slog.d(CentralSurfaces.TAG, "Can't launch camera right now"); } return; } - if (!mStatusBar.isDeviceInteractive()) { + if (!mCentralSurfaces.isDeviceInteractive()) { mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH, "com.android.systemui:CAMERA_GESTURE"); } vibrateForCameraGesture(); if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) { - Log.v(StatusBar.TAG, "Camera launch"); + Log.v(CentralSurfaces.TAG, "Camera launch"); mKeyguardUpdateMonitor.onCameraLaunched(); } if (!mStatusBarKeyguardViewManager.isShowing()) { final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext); - mStatusBar.startActivityDismissingKeyguard(cameraIntent, + mCentralSurfaces.startActivityDismissingKeyguard(cameraIntent, false /* onlyProvisioned */, true /* dismissShade */, true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0, null /* animationController */); } else { - if (!mStatusBar.isDeviceInteractive()) { + if (!mCentralSurfaces.isDeviceInteractive()) { // Avoid flickering of the scrim when we instant launch the camera and the bouncer // comes on. - mStatusBar.acquireGestureWakeLock(StatusBar.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L); + mCentralSurfaces.acquireGestureWakeLock( + CentralSurfaces.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L); } if (isWakingUpOrAwake()) { - if (StatusBar.DEBUG_CAMERA_LIFT) { - Slog.d(StatusBar.TAG, "Launching camera"); + if (CentralSurfaces.DEBUG_CAMERA_LIFT) { + Slog.d(CentralSurfaces.TAG, "Launching camera"); } if (mStatusBarKeyguardViewManager.isBouncerShowing()) { mStatusBarKeyguardViewManager.reset(true /* hide */); } mNotificationPanelViewController.launchCamera( - mStatusBar.isDeviceInteractive() /* animate */, source); - mStatusBar.updateScrimController(); + mCentralSurfaces.isDeviceInteractive() /* animate */, source); + mCentralSurfaces.updateScrimController(); } else { // We need to defer the camera launch until the screen comes on, since otherwise // we will dismiss us too early since we are waiting on an activity to be drawn and // incorrectly get notified because of the screen on event (which resumes and pauses // some activities) - if (StatusBar.DEBUG_CAMERA_LIFT) { - Slog.d(StatusBar.TAG, "Deferring until screen turns on"); + if (CentralSurfaces.DEBUG_CAMERA_LIFT) { + Slog.d(CentralSurfaces.TAG, "Deferring until screen turns on"); } - mStatusBar.setLaunchCameraOnFinishedWaking(true); + mCentralSurfaces.setLaunchCameraOnFinishedWaking(true); } } } @Override public void onEmergencyActionLaunchGestureDetected() { - Intent emergencyIntent = mStatusBar.getEmergencyActionIntent(); + Intent emergencyIntent = mCentralSurfaces.getEmergencyActionIntent(); if (emergencyIntent == null) { - Log.wtf(StatusBar.TAG, "Couldn't find an app to process the emergency intent."); + Log.wtf(CentralSurfaces.TAG, "Couldn't find an app to process the emergency intent."); return; } if (isGoingToSleep()) { - mStatusBar.setLaunchEmergencyActionOnFinishedGoingToSleep(true); + mCentralSurfaces.setLaunchEmergencyActionOnFinishedGoingToSleep(true); return; } - if (!mStatusBar.isDeviceInteractive()) { + if (!mCentralSurfaces.isDeviceInteractive()) { mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:EMERGENCY_GESTURE"); @@ -424,17 +425,18 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { // app-side haptic experimentation. if (!mStatusBarKeyguardViewManager.isShowing()) { - mStatusBar.startActivityDismissingKeyguard(emergencyIntent, + mCentralSurfaces.startActivityDismissingKeyguard(emergencyIntent, false /* onlyProvisioned */, true /* dismissShade */, true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0, null /* animationController */); return; } - if (!mStatusBar.isDeviceInteractive()) { + if (!mCentralSurfaces.isDeviceInteractive()) { // Avoid flickering of the scrim when we instant launch the camera and the bouncer // comes on. - mStatusBar.acquireGestureWakeLock(StatusBar.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L); + mCentralSurfaces.acquireGestureWakeLock( + CentralSurfaces.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L); } if (isWakingUpOrAwake()) { @@ -448,12 +450,12 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { // we will dismiss us too early since we are waiting on an activity to be drawn and // incorrectly get notified because of the screen on event (which resumes and pauses // some activities) - mStatusBar.setLaunchEmergencyActionOnFinishedWaking(true); + mCentralSurfaces.setLaunchEmergencyActionOnFinishedWaking(true); } @Override public void onRecentsAnimationStateChanged(boolean running) { - mStatusBar.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, running); + mCentralSurfaces.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, running); } @@ -464,12 +466,12 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { if (displayId != mDisplayId) { return; } - boolean barModeChanged = mStatusBar.setAppearance(appearance); + boolean barModeChanged = mCentralSurfaces.setAppearance(appearance); mLightBarController.onStatusBarAppearanceChanged(appearanceRegions, barModeChanged, - mStatusBar.getBarMode(), navbarColorManagedByIme); + mCentralSurfaces.getBarMode(), navbarColorManagedByIme); - mStatusBar.updateBubblesVisibility(); + mCentralSurfaces.updateBubblesVisibility(); mStatusBarStateController.setSystemBarAttributes( appearance, behavior, requestedVisibilities, packageName); } @@ -483,12 +485,12 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { if (!containsType(types, ITYPE_STATUS_BAR)) { return; } - mStatusBar.showTransientUnchecked(); + mCentralSurfaces.showTransientUnchecked(); } @Override public void toggleKeyboardShortcutsMenu(int deviceId) { - mStatusBar.resendMessage(new StatusBar.KeyboardShortcutsMessage(deviceId)); + mCentralSurfaces.resendMessage(new CentralSurfaces.KeyboardShortcutsMessage(deviceId)); } @Override @@ -504,12 +506,12 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { @Override public void showPinningEnterExitToast(boolean entering) { - mStatusBar.showPinningEnterExitToast(entering); + mCentralSurfaces.showPinningEnterExitToast(entering); } @Override public void showPinningEscapeToast() { - mStatusBar.showPinningEscapeToast(); + mCentralSurfaces.showPinningEscapeToast(); } @Override @@ -519,12 +521,12 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { return; } // Show screen pinning request, since this comes from an app, show 'no thanks', button. - mStatusBar.showScreenPinningRequest(taskId, true); + mCentralSurfaces.showScreenPinningRequest(taskId, true); } @Override public void showWirelessChargingAnimation(int batteryLevel) { - mStatusBar.showWirelessChargingAnimation(batteryLevel); + mCentralSurfaces.showWirelessChargingAnimation(batteryLevel); } @Override @@ -534,12 +536,12 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { @Override public void suppressAmbientDisplay(boolean suppressed) { - mDozeServiceHost.setDozeSuppressed(suppressed); + mDozeServiceHost.setAlwaysOnSuppressed(suppressed); } @Override public void togglePanel() { - if (mStatusBar.isPanelExpanded()) { + if (mCentralSurfaces.isPanelExpanded()) { mShadeController.animateCollapsePanels(); } else { animateExpandNotificationsPanel(); @@ -576,8 +578,8 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { // Make sure to pass -1 for repeat so VibratorManagerService doesn't stop us when going // to sleep. return VibrationEffect.createWaveform( - StatusBar.CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS, - StatusBar.CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES, + CentralSurfaces.CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS, + CentralSurfaces.CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES, /* repeat= */ -1); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index 8b25c2bc20b9..ebe91c7dc5d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -292,11 +292,20 @@ public class DozeParameters implements } public void updateControlScreenOff() { - if (!getDisplayNeedsBlanking()) { - final boolean controlScreenOff = - getAlwaysOn() && (mKeyguardShowing || shouldControlUnlockedScreenOff()); - setControlScreenOffAnimation(controlScreenOff); - } + final boolean controlScreenOff = shouldControlUnlockedScreenOff() + || (!getDisplayNeedsBlanking() && getAlwaysOn() && mKeyguardShowing); + setControlScreenOffAnimation(controlScreenOff); + } + + /** + * Whether we're capable of controlling the screen off animation if we want to. This isn't + * possible if AOD isn't even enabled or if the flag is disabled, or if the display needs + * blanking. + */ + public boolean canControlUnlockedScreenOff() { + return getAlwaysOn() + && mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS) + && !getDisplayNeedsBlanking(); } /** @@ -309,8 +318,7 @@ public class DozeParameters implements * disabled for a11y. */ public boolean shouldControlUnlockedScreenOff() { - return canControlUnlockedScreenOff() - && mUnlockedScreenOffAnimationController.shouldPlayUnlockedScreenOffAnimation(); + return mUnlockedScreenOffAnimationController.shouldPlayUnlockedScreenOffAnimation(); } public boolean shouldDelayKeyguardShow() { @@ -342,16 +350,6 @@ public class DozeParameters implements return getAlwaysOn() && mKeyguardShowing; } - /** - * Whether we're capable of controlling the screen off animation if we want to. This isn't - * possible if AOD isn't even enabled or if the flag is disabled. - */ - public boolean canControlUnlockedScreenOff() { - return getAlwaysOn() - && mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS) - && !getDisplayNeedsBlanking(); - } - private boolean getBoolean(String propName, int resId) { return SystemProperties.getBoolean(propName, mResources.getBoolean(resId)); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java index 05fba5498ea7..55b310ff986d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java @@ -97,8 +97,8 @@ public final class DozeServiceHost implements DozeHost { private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private NotificationPanelViewController mNotificationPanel; private View mAmbientIndicationContainer; - private StatusBar mStatusBar; - private boolean mSuppressed; + private CentralSurfaces mCentralSurfaces; + private boolean mAlwaysOnSuppressed; @Inject public DozeServiceHost(DozeLog dozeLog, PowerManager powerManager, @@ -146,12 +146,12 @@ public final class DozeServiceHost implements DozeHost { * Initialize instance with objects only available later during execution. */ public void initialize( - StatusBar statusBar, + CentralSurfaces centralSurfaces, StatusBarKeyguardViewManager statusBarKeyguardViewManager, NotificationShadeWindowViewController notificationShadeWindowViewController, NotificationPanelViewController notificationPanel, View ambientIndicationContainer) { - mStatusBar = statusBar; + mCentralSurfaces = centralSurfaces; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mNotificationPanel = notificationPanel; mNotificationShadeWindowViewController = notificationShadeWindowViewController; @@ -205,7 +205,7 @@ public final class DozeServiceHost implements DozeHost { mDozingRequested = true; updateDozing(); mDozeLog.traceDozing(mStatusBarStateController.isDozing()); - mStatusBar.updateIsKeyguard(); + mCentralSurfaces.updateIsKeyguard(); } } @@ -247,13 +247,13 @@ public final class DozeServiceHost implements DozeHost { && mWakeLockScreenPerformsAuth; // Set the state to pulsing, so ScrimController will know what to do once we ask it to // execute the transition. The pulse callback will then be invoked when the scrims - // are black, indicating that StatusBar is ready to present the rest of the UI. + // are black, indicating that CentralSurfaces is ready to present the rest of the UI. mPulsing = true; mDozeScrimController.pulse(new PulseCallback() { @Override public void onPulseStarted() { callback.onPulseStarted(); - mStatusBar.updateNotificationPanelTouchState(); + mCentralSurfaces.updateNotificationPanelTouchState(); setPulsing(true); } @@ -261,7 +261,7 @@ public final class DozeServiceHost implements DozeHost { public void onPulseFinished() { mPulsing = false; callback.onPulseFinished(); - mStatusBar.updateNotificationPanelTouchState(); + mCentralSurfaces.updateNotificationPanelTouchState(); mScrimController.setWakeLockScreenSensorActive(false); setPulsing(false); } @@ -274,14 +274,14 @@ public final class DozeServiceHost implements DozeHost { if (mKeyguardUpdateMonitor != null && passiveAuthInterrupt) { mKeyguardUpdateMonitor.onAuthInterruptDetected(pulsing /* active */); } - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); mPulseExpansionHandler.setPulsing(pulsing); mNotificationWakeUpCoordinator.setPulsing(pulsing); } }, reason); // DozeScrimController is in pulse state, now let's ask ScrimController to start // pulsing and draw the black frame, if necessary. - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); } @Override @@ -332,15 +332,6 @@ public final class DozeServiceHost implements DozeHost { } @Override - public boolean isBlockingDoze() { - if (mBiometricUnlockControllerLazy.get().hasPendingAuthentication()) { - Log.i(StatusBar.TAG, "Blocking AOD because fingerprint has authenticated"); - return true; - } - return false; - } - - @Override public void extendPulse(int reason) { if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH) { mScrimController.setWakeLockScreenSensorActive(true); @@ -412,14 +403,14 @@ public final class DozeServiceHost implements DozeHost { Log.w(TAG, "Overlapping onDisplayOffCallback. Ignoring previous one."); } mPendingScreenOffCallback = onDisplayOffCallback; - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); } @Override public void cancelGentleSleep() { mPendingScreenOffCallback = null; if (mScrimController.getState() == ScrimState.OFF) { - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); } } @@ -452,18 +443,25 @@ public final class DozeServiceHost implements DozeHost { return mIgnoreTouchWhilePulsing; } - void setDozeSuppressed(boolean suppressed) { - if (suppressed == mSuppressed) { + /** + * Suppresses always-on-display and waking up the display for notifications. + * Does not disable wakeup gestures like pickup and tap. + */ + void setAlwaysOnSuppressed(boolean suppressed) { + if (suppressed == mAlwaysOnSuppressed) { return; } - mSuppressed = suppressed; - mDozeLog.traceDozingSuppressed(mSuppressed); + mAlwaysOnSuppressed = suppressed; for (Callback callback : mCallbacks) { - callback.onDozeSuppressedChanged(suppressed); + callback.onAlwaysOnSuppressedChanged(suppressed); } } - public boolean isDozeSuppressed() { - return mSuppressed; + /** + * Whether always-on-display is being suppressed. This does not affect wakeup gestures like + * pickup and tap. + */ + public boolean isAlwaysOnSuppressed() { + return mAlwaysOnSuppressed; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 84103c0bb377..541aeab22a80 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -118,7 +118,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL KeyguardStateController.Callback, AccessibilityController.AccessibilityStateChangedCallback { - final static String TAG = "StatusBar/KeyguardBottomAreaView"; + final static String TAG = "CentralSurfaces/KeyguardBottomAreaView"; public static final String CAMERA_LAUNCH_SOURCE_AFFORDANCE = "lockscreen_affordance"; public static final String CAMERA_LAUNCH_SOURCE_WIGGLE = "wiggle_gesture"; @@ -169,7 +169,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private FlashlightController mFlashlightController; private PreviewInflater mPreviewInflater; private AccessibilityController mAccessibilityController; - private StatusBar mStatusBar; + private CentralSurfaces mCentralSurfaces; private KeyguardAffordanceHelper mAffordanceHelper; private FalsingManager mFalsingManager; private boolean mUserSetupComplete; @@ -274,7 +274,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL }; public void initFrom(KeyguardBottomAreaView oldBottomArea) { - setStatusBar(oldBottomArea.mStatusBar); + setCentralSurfaces(oldBottomArea.mCentralSurfaces); // if it exists, continue to use the original ambient indication container // instead of the newly inflated one @@ -473,8 +473,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mRightAffordanceView.setContentDescription(state.contentDescription); } - public void setStatusBar(StatusBar statusBar) { - mStatusBar = statusBar; + public void setCentralSurfaces(CentralSurfaces centralSurfaces) { + mCentralSurfaces = centralSurfaces; updateCameraVisibility(); // in case onFinishInflate() was called too early } @@ -732,7 +732,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } else { boolean dismissShade = !TextUtils.isEmpty(mRightButtonStr) && Dependency.get(TunerService.class).getValue(LOCKSCREEN_RIGHT_UNLOCK, 1) != 0; - mStatusBar.executeRunnableDismissingKeyguard(runnable, null /* cancelAction */, + mCentralSurfaces.executeRunnableDismissingKeyguard(runnable, null /* cancelAction */, dismissShade, false /* afterKeyguardGone */, true /* deferred */); } } @@ -1019,7 +1019,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override public IconState getIcon() { - boolean isCameraDisabled = (mStatusBar != null) && !mStatusBar.isCameraAllowedByAdmin(); + boolean isCameraDisabled = (mCentralSurfaces != null) + && !mCentralSurfaces.isCameraAllowedByAdmin(); mIconState.isVisible = !isCameraDisabled && mShowCameraAffordance && mUserSetupComplete diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java index 9bdefcd98422..2c4fc6c6f734 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java @@ -14,8 +14,8 @@ package com.android.systemui.statusbar.phone; -import static com.android.systemui.statusbar.phone.StatusBar.DEBUG; -import static com.android.systemui.statusbar.phone.StatusBar.MULTIUSER_DEBUG; +import static com.android.systemui.statusbar.phone.CentralSurfaces.DEBUG; +import static com.android.systemui.statusbar.phone.CentralSurfaces.MULTIUSER_DEBUG; import android.service.notification.StatusBarNotification; import android.util.Log; 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 a0f8d05ebd0e..01860a822503 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -184,11 +184,12 @@ import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.MediaContainerView; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.phone.panelstate.PanelState; @@ -221,7 +222,7 @@ import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Provider; -@StatusBarComponent.StatusBarScope +@CentralSurfacesComponent.CentralSurfacesScope public class NotificationPanelViewController extends PanelViewController implements NotifPanelEventSource { @@ -665,6 +666,8 @@ public class NotificationPanelViewController extends PanelViewController private final ListenerSet<Callbacks> mNotifEventSourceCallbacks = new ListenerSet<>(); + private final NotificationListContainer mNotificationListContainer; + private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() { @Override public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { @@ -792,7 +795,8 @@ public class NotificationPanelViewController extends PanelViewController InteractionJankMonitor interactionJankMonitor, QsFrameTranslateController qsFrameTranslateController, SysUiState sysUiState, - KeyguardUnlockAnimationController keyguardUnlockAnimationController) { + KeyguardUnlockAnimationController keyguardUnlockAnimationController, + NotificationListContainer notificationListContainer) { super(view, falsingManager, dozeLog, @@ -823,6 +827,7 @@ public class NotificationPanelViewController extends PanelViewController mMediaHierarchyManager = mediaHierarchyManager; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mNotificationsQSContainerController = notificationsQSContainerController; + mNotificationListContainer = notificationListContainer; mNotificationsQSContainerController.init(); mNotificationStackScrollLayoutController = notificationStackScrollLayoutController; mGroupManager = groupManager; @@ -1127,10 +1132,10 @@ public class NotificationPanelViewController extends PanelViewController return mKeyguardStatusViewController.hasCustomClock(); } - private void setStatusBar(StatusBar bar) { + private void setCentralSurfaces(CentralSurfaces centralSurfaces) { // TODO: this can be injected. - mStatusBar = bar; - mKeyguardBottomArea.setStatusBar(mStatusBar); + mCentralSurfaces = centralSurfaces; + mKeyguardBottomArea.setCentralSurfaces(mCentralSurfaces); } public void updateResources() { @@ -1139,10 +1144,16 @@ public class NotificationPanelViewController extends PanelViewController mSplitShadeNotificationsScrimMarginBottom = mResources.getDimensionPixelSize( R.dimen.split_shade_notifications_scrim_margin_bottom); - int qsWidth = mResources.getDimensionPixelSize(R.dimen.qs_panel_width); - int panelWidth = mResources.getDimensionPixelSize(R.dimen.notification_panel_width); - mShouldUseSplitNotificationShade = + + int panelMarginHorizontal = mResources.getDimensionPixelSize( + R.dimen.notification_panel_margin_horizontal); + + final boolean newShouldUseSplitNotificationShade = Utils.shouldUseSplitNotificationShade(mResources); + final boolean splitNotificationShadeChanged = + mShouldUseSplitNotificationShade != newShouldUseSplitNotificationShade; + + mShouldUseSplitNotificationShade = newShouldUseSplitNotificationShade; if (mQs != null) { mQs.setInSplitShade(mShouldUseSplitNotificationShade); } @@ -1157,11 +1168,12 @@ public class NotificationPanelViewController extends PanelViewController ensureAllViewsHaveIds(mNotificationContainerParent); ConstraintSet constraintSet = new ConstraintSet(); constraintSet.clone(mNotificationContainerParent); - + int statusViewMarginHorizontal = mResources.getDimensionPixelSize( + R.dimen.status_view_margin_horizontal); + constraintSet.setMargin(R.id.keyguard_status_view, START, statusViewMarginHorizontal); + constraintSet.setMargin(R.id.keyguard_status_view, END, statusViewMarginHorizontal); if (mShouldUseSplitNotificationShade) { // width = 0 to take up all available space within constraints - qsWidth = 0; - panelWidth = 0; constraintSet.connect(R.id.qs_frame, END, R.id.qs_edge_guideline, END); constraintSet.connect( R.id.notification_stack_scroller, START, @@ -1174,11 +1186,15 @@ public class NotificationPanelViewController extends PanelViewController constraintSet.constrainHeight(R.id.split_shade_status_bar, WRAP_CONTENT); } } - constraintSet.getConstraint(R.id.notification_stack_scroller).layout.mWidth = panelWidth; - constraintSet.getConstraint(R.id.qs_frame).layout.mWidth = qsWidth; + constraintSet.setMargin(R.id.notification_stack_scroller, START, + mShouldUseSplitNotificationShade ? 0 : panelMarginHorizontal); + constraintSet.setMargin(R.id.notification_stack_scroller, END, panelMarginHorizontal); constraintSet.setMargin(R.id.notification_stack_scroller, TOP, topMargin); constraintSet.setMargin(R.id.notification_stack_scroller, BOTTOM, notificationsBottomMargin); + constraintSet.setMargin(R.id.qs_frame, START, panelMarginHorizontal); + constraintSet.setMargin(R.id.qs_frame, END, + mShouldUseSplitNotificationShade ? 0 : panelMarginHorizontal); constraintSet.setMargin(R.id.qs_frame, TOP, topMargin); constraintSet.applyTo(mNotificationContainerParent); mAmbientState.setStackTopMargin(topMargin); @@ -1188,6 +1204,10 @@ public class NotificationPanelViewController extends PanelViewController updateKeyguardStatusViewAlignment(/* animate= */false); mKeyguardMediaController.refreshMediaPosition(); + + if (splitNotificationShadeChanged) { + updateClockAppearance(); + } } private static void ensureAllViewsHaveIds(ViewGroup parentView) { @@ -1311,7 +1331,7 @@ public class NotificationPanelViewController extends PanelViewController mAffordanceHelper = new KeyguardAffordanceHelper( mKeyguardAffordanceHelperCallback, mView.getContext(), mFalsingManager); mKeyguardBottomArea.setAffordanceHelper(mAffordanceHelper); - mKeyguardBottomArea.setStatusBar(mStatusBar); + mKeyguardBottomArea.setCentralSurfaces(mCentralSurfaces); mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete); mKeyguardBottomArea.setFalsingManager(mFalsingManager); mKeyguardBottomArea.initWallet(mQuickAccessWalletController); @@ -1574,7 +1594,7 @@ public class NotificationPanelViewController extends PanelViewController float lockIconPadding = 0; if (mLockIconViewController.getTop() != 0) { - lockIconPadding = mStatusBar.getDisplayHeight() - mLockIconViewController.getTop() + lockIconPadding = mCentralSurfaces.getDisplayHeight() - mLockIconViewController.getTop() + mResources.getDimensionPixelSize(R.dimen.min_lock_icon_padding); } @@ -1728,7 +1748,7 @@ public class NotificationPanelViewController extends PanelViewController mAffordanceHelper.reset(false); mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE; } - mStatusBar.getGutsManager().closeAndSaveGuts(true /* leavebehind */, true /* force */, + mCentralSurfaces.getGutsManager().closeAndSaveGuts(true /* leavebehind */, true /* force */, true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */); if (animate && !isFullyCollapsed()) { animateCloseQs(true /* animateAway */); @@ -1827,7 +1847,7 @@ public class NotificationPanelViewController extends PanelViewController @Override public void fling(float vel, boolean expand) { - GestureRecorder gr = mStatusBar.getGestureRecorder(); + GestureRecorder gr = mCentralSurfaces.getGestureRecorder(); if (gr != null) { gr.tag("fling " + ((vel > 0) ? "open" : "closed"), "notifications,v=" + vel); } @@ -2016,8 +2036,8 @@ public class NotificationPanelViewController extends PanelViewController mBarState == KEYGUARD ? MetricsEvent.ACTION_LS_QS : MetricsEvent.ACTION_SHADE_QS_PULL; mLockscreenGestureLogger.write(gesture, - (int) ((y - mInitialTouchY) / mStatusBar.getDisplayDensity()), - (int) (vel / mStatusBar.getDisplayDensity())); + (int) ((y - mInitialTouchY) / mCentralSurfaces.getDisplayDensity()), + (int) (vel / mCentralSurfaces.getDisplayDensity())); } private boolean flingExpandsQs(float vel) { @@ -2295,7 +2315,7 @@ public class NotificationPanelViewController extends PanelViewController } private int getFalsingThreshold() { - float factor = mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f; + float factor = mCentralSurfaces.isWakeUpComingFromTouch() ? 1.5f : 1.0f; return (int) (mQsFalsingThreshold * factor); } @@ -2322,7 +2342,7 @@ public class NotificationPanelViewController extends PanelViewController // When expanding QS, let's authenticate the user if possible, // this will speed up notification actions. if (height == 0) { - mStatusBar.requestFaceAuth(false); + mCentralSurfaces.requestFaceAuth(false); } } @@ -2333,7 +2353,7 @@ public class NotificationPanelViewController extends PanelViewController updateQsState(); requestPanelHeightUpdate(); mFalsingCollector.setQsExpanded(expanded); - mStatusBar.setQsExpanded(expanded); + mCentralSurfaces.setQsExpanded(expanded); mNotificationsQSContainerController.setQsExpanded(expanded); mPulseExpansionHandler.setQsExpanded(expanded); mKeyguardBypassController.setQSExpanded(expanded); @@ -2417,7 +2437,7 @@ public class NotificationPanelViewController extends PanelViewController if (!mFalsingManager.isUnlockingDisabled() && mQsFullyExpanded && mFalsingCollector.shouldEnforceBouncer()) { - mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */, + mCentralSurfaces.executeRunnableDismissingKeyguard(null, null /* cancelAction */, false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */); } if (DEBUG) { @@ -3105,7 +3125,7 @@ public class NotificationPanelViewController extends PanelViewController if (mPanelExpanded != isExpanded) { mHeadsUpManager.setIsPanelExpanded(isExpanded); mStatusBarTouchableRegionManager.setPanelExpanded(isExpanded); - mStatusBar.setPanelExpanded(isExpanded); + mCentralSurfaces.setPanelExpanded(isExpanded); mPanelExpanded = isExpanded; if (!isExpanded && mQs != null && mQs.isCustomizing()) { @@ -3230,7 +3250,7 @@ public class NotificationPanelViewController extends PanelViewController mKeyguardBottomArea.setImportantForAccessibility( alpha == 0f ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); - View ambientIndicationContainer = mStatusBar.getAmbientIndicationContainer(); + View ambientIndicationContainer = mCentralSurfaces.getAmbientIndicationContainer(); if (ambientIndicationContainer != null) { ambientIndicationContainer.setAlpha(alpha); } @@ -3569,7 +3589,7 @@ public class NotificationPanelViewController extends PanelViewController @Override protected void onClosingFinished() { - mStatusBar.onClosingFinished(); + mCentralSurfaces.onClosingFinished(); setClosingWithAlphaFadeout(false); mMediaHierarchyManager.closeGuts(); } @@ -3631,7 +3651,7 @@ public class NotificationPanelViewController extends PanelViewController } public void clearNotificationEffects() { - mStatusBar.clearNotificationEffects(); + mCentralSurfaces.clearNotificationEffects(); } @Override @@ -3693,7 +3713,7 @@ public class NotificationPanelViewController extends PanelViewController * Whether the camera application can be launched for the camera launch gesture. */ public boolean canCameraGestureBeLaunched() { - if (!mStatusBar.isCameraAllowedByAdmin()) { + if (!mCentralSurfaces.isCameraAllowedByAdmin()) { return false; } @@ -4037,8 +4057,7 @@ public class NotificationPanelViewController extends PanelViewController } public boolean hasPulsingNotifications() { - return mNotificationStackScrollLayoutController - .getNotificationListContainer().hasPulsingNotifications(); + return mNotificationListContainer.hasPulsingNotifications(); } public ActivatableNotificationView getActivatedChild() { @@ -4073,10 +4092,10 @@ public class NotificationPanelViewController extends PanelViewController * @param hideExpandedRunnable a runnable to run when we need to hide the expanded panel. */ public void initDependencies( - StatusBar statusBar, + CentralSurfaces centralSurfaces, Runnable hideExpandedRunnable, NotificationShelfController notificationShelfController) { - setStatusBar(statusBar); + setCentralSurfaces(centralSurfaces); mHideExpandedRunnable = hideExpandedRunnable; mNotificationStackScrollLayoutController.setShelfController(notificationShelfController); mNotificationShelfController = notificationShelfController; @@ -4149,7 +4168,7 @@ public class NotificationPanelViewController extends PanelViewController initDownStates(event); // Do not let touches go to shade or QS if the bouncer is visible, // but still let user swipe down to expand the panel, dismissing the bouncer. - if (mStatusBar.isBouncerShowing()) { + if (mCentralSurfaces.isBouncerShowing()) { return true; } if (mCommandQueue.panelsEnabled() @@ -4192,8 +4211,8 @@ public class NotificationPanelViewController extends PanelViewController // Do not allow panel expansion if bouncer is scrimmed or showing over a dream, // otherwise user would be able to pull down QS or expand the shade. - if (mStatusBar.isBouncerShowingScrimmed() - || mStatusBar.isBouncerShowingOverDream()) { + if (mCentralSurfaces.isBouncerShowingScrimmed() + || mCentralSurfaces.isBouncerShowingOverDream()) { return false; } @@ -4257,15 +4276,15 @@ public class NotificationPanelViewController extends PanelViewController new PhoneStatusBarView.TouchEventHandler() { @Override public void onInterceptTouchEvent(MotionEvent event) { - mStatusBar.onTouchEvent(event); + mCentralSurfaces.onTouchEvent(event); } @Override public boolean handleTouchEvent(MotionEvent event) { - mStatusBar.onTouchEvent(event); + mCentralSurfaces.onTouchEvent(event); // TODO(b/202981994): Move the touch debugging in this method to a central - // location. (Right now, it's split between StatusBar and here.) + // location. (Right now, it's split between CentralSurfaces and here.) // If panels aren't enabled, ignore the gesture and don't pass it down to the // panel view. @@ -4482,7 +4501,7 @@ public class NotificationPanelViewController extends PanelViewController : !rightPage; mIsLaunchTransitionRunning = true; mLaunchAnimationEndRunnable = null; - float displayDensity = mStatusBar.getDisplayDensity(); + float displayDensity = mCentralSurfaces.getDisplayDensity(); int lengthDp = Math.abs((int) (translation / displayDensity)); int velocityDp = Math.abs((int) (vel / displayDensity)); if (start) { @@ -4490,7 +4509,7 @@ public class NotificationPanelViewController extends PanelViewController mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_DIALER); mFalsingCollector.onLeftAffordanceOn(); if (mFalsingCollector.shouldEnforceBouncer()) { - mStatusBar.executeRunnableDismissingKeyguard( + mCentralSurfaces.executeRunnableDismissingKeyguard( () -> mKeyguardBottomArea.launchLeftAffordance(), null, true /* dismissShade */, false /* afterKeyguardGone */, true /* deferred */); @@ -4506,7 +4525,7 @@ public class NotificationPanelViewController extends PanelViewController } mFalsingCollector.onCameraOn(); if (mFalsingCollector.shouldEnforceBouncer()) { - mStatusBar.executeRunnableDismissingKeyguard( + mCentralSurfaces.executeRunnableDismissingKeyguard( () -> mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource), null, true /* dismissShade */, false /* afterKeyguardGone */, true /* deferred */); @@ -4514,7 +4533,7 @@ public class NotificationPanelViewController extends PanelViewController mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource); } } - mStatusBar.startLaunchTransitionTimeout(); + mCentralSurfaces.startLaunchTransitionTimeout(); mBlockTouches = true; } @@ -4526,7 +4545,7 @@ public class NotificationPanelViewController extends PanelViewController mLaunchAnimationEndRunnable.run(); mLaunchAnimationEndRunnable = null; } - mStatusBar.readyForKeyguardDone(); + mCentralSurfaces.readyForKeyguardDone(); } @Override @@ -4563,18 +4582,18 @@ public class NotificationPanelViewController extends PanelViewController mHintAnimationRunning = true; mAffordanceHelper.startHintAnimation(rightIcon, () -> { mHintAnimationRunning = false; - mStatusBar.onHintFinished(); + mCentralSurfaces.onHintFinished(); }); rightIcon = mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? !rightIcon : rightIcon; if (rightIcon) { - mStatusBar.onCameraHintStarted(); + mCentralSurfaces.onCameraHintStarted(); } else { if (mKeyguardBottomArea.isLeftVoiceAssist()) { - mStatusBar.onVoiceAssistHintStarted(); + mCentralSurfaces.onVoiceAssistHintStarted(); } else { - mStatusBar.onPhoneHintStarted(); + mCentralSurfaces.onPhoneHintStarted(); } } } @@ -4605,7 +4624,7 @@ public class NotificationPanelViewController extends PanelViewController @Override public float getAffordanceFalsingFactor() { - return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f; + return mCentralSurfaces.isWakeUpComingFromTouch() ? 1.5f : 1.0f; } @Override @@ -5121,7 +5140,7 @@ public class NotificationPanelViewController extends PanelViewController mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); } if (state == STATE_OPENING) { - mStatusBar.makeExpandedVisible(false); + mCentralSurfaces.makeExpandedVisible(false); } if (state == STATE_CLOSED) { // Close the status bar in the next frame so we can show the end of the diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java index 5caf4f604fcd..0ff010aedfff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java @@ -840,7 +840,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW Set<String> mComponentsForcingTopUi = new HashSet<>(); /** - * The {@link StatusBar} state from the status bar. + * The status bar state from {@link CentralSurfaces}. */ int mStatusBarState; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java index fb0e306b2e8b..1e3a02b0606b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java @@ -58,7 +58,7 @@ import com.android.systemui.R; */ public class NotificationShadeWindowView extends FrameLayout { public static final String TAG = "NotificationShadeWindowView"; - public static final boolean DEBUG = StatusBar.DEBUG; + public static final boolean DEBUG = CentralSurfaces.DEBUG; private int mRightInset = 0; private int mLeftInset = 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java index 396703b11a42..101c86f6dac1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java @@ -44,6 +44,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.tuner.TunerService; @@ -57,6 +58,7 @@ import javax.inject.Inject; /** * Controller for {@link NotificationShadeWindowView}. */ +@CentralSurfacesComponent.CentralSurfacesScope public class NotificationShadeWindowViewController { private static final String TAG = "NotifShadeWindowVC"; private final FalsingCollector mFalsingCollector; @@ -77,8 +79,8 @@ public class NotificationShadeWindowViewController { private boolean mExpandAnimationRunning; private NotificationStackScrollLayout mStackScrollLayout; private PhoneStatusBarViewController mStatusBarViewController; - private StatusBar mService; - private NotificationShadeWindowController mNotificationShadeWindowController; + private final CentralSurfaces mService; + private final NotificationShadeWindowController mNotificationShadeWindowController; private DragDownHelper mDragDownHelper; private boolean mDoubleTapEnabled; private boolean mSingleTapEnabled; @@ -105,7 +107,9 @@ public class NotificationShadeWindowViewController { StatusBarKeyguardViewManager statusBarKeyguardViewManager, StatusBarWindowStateController statusBarWindowStateController, LockIconViewController lockIconViewController, - Optional<LowLightClockController> lowLightClockController) { + Optional<LowLightClockController> lowLightClockController, + CentralSurfaces centralSurfaces, + NotificationShadeWindowController controller) { mLockscreenShadeTransitionController = transitionController; mFalsingCollector = falsingCollector; mTunerService = tunerService; @@ -120,6 +124,8 @@ public class NotificationShadeWindowViewController { mStatusBarWindowStateController = statusBarWindowStateController; mLockIconViewController = lockIconViewController; mLowLightClockController = lowLightClockController; + mService = centralSurfaces; + mNotificationShadeWindowController = controller; // This view is not part of the newly inflated expanded status bar. mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container); @@ -452,11 +458,6 @@ public class NotificationShadeWindowViewController { mStatusBarViewController = statusBarViewController; } - public void setService(StatusBar statusBar, NotificationShadeWindowController controller) { - mService = statusBar; - mNotificationShadeWindowController = controller; - } - /** * Tell the controller that dozing has begun or ended. * @param dozing True if dozing has begun. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 249f9886253c..45dc943de2f8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -27,7 +27,7 @@ public abstract class PanelView extends FrameLayout { public static final String TAG = PanelView.class.getSimpleName(); private PanelViewController.TouchHandler mTouchHandler; - protected StatusBar mStatusBar; + protected CentralSurfaces mCentralSurfaces; protected HeadsUpManagerPhone mHeadsUpManager; protected KeyguardBottomAreaView mKeyguardBottomArea; 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 85e804233ed9..7c1775ed2a5e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -113,7 +113,7 @@ public abstract class PanelViewController { Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args)); } - protected StatusBar mStatusBar; + protected CentralSurfaces mCentralSurfaces; protected HeadsUpManagerPhone mHeadsUpManager; protected final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager; @@ -349,9 +349,9 @@ public abstract class PanelViewController { //TODO: keyguard opens QS a different way; log that too? // Log the position of the swipe that opened the panel - float width = mStatusBar.getDisplayWidth(); - float height = mStatusBar.getDisplayHeight(); - int rot = mStatusBar.getRotation(); + float width = mCentralSurfaces.getDisplayWidth(); + float height = mCentralSurfaces.getDisplayHeight(); + int rot = mCentralSurfaces.getRotation(); mLockscreenGestureLogger.writeAtFractionalPosition(MetricsEvent.ACTION_PANEL_VIEW_EXPAND, (int) (event.getX() / width * 100), (int) (event.getY() / height * 100), rot); @@ -433,10 +433,11 @@ public abstract class PanelViewController { } mDozeLog.traceFling(expand, mTouchAboveFalsingThreshold, - mStatusBar.isFalsingThresholdNeeded(), mStatusBar.isWakeUpComingFromTouch()); + mCentralSurfaces.isFalsingThresholdNeeded(), + mCentralSurfaces.isWakeUpComingFromTouch()); // Log collapse gesture if on lock screen. if (!expand && onKeyguard) { - float displayDensity = mStatusBar.getDisplayDensity(); + float displayDensity = mCentralSurfaces.getDisplayDensity(); int heightDp = (int) Math.abs((y - mInitialTouchY) / displayDensity); int velocityDp = (int) Math.abs(vel / displayDensity); mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_UNLOCK, heightDp, velocityDp); @@ -453,7 +454,7 @@ public abstract class PanelViewController { if (mUpdateFlingOnLayout) { mUpdateFlingVelocity = vel; } - } else if (!mStatusBar.isBouncerShowing() + } else if (!mCentralSurfaces.isBouncerShowing() && !mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating() && !mKeyguardStateController.isKeyguardGoingAway()) { boolean expands = onEmptySpaceClick(mInitialTouchX); @@ -469,7 +470,7 @@ public abstract class PanelViewController { } private int getFalsingThreshold() { - float factor = mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f; + float factor = mCentralSurfaces.isWakeUpComingFromTouch() ? 1.5f : 1.0f; return (int) (mUnlockFalsingThreshold * factor); } @@ -479,14 +480,14 @@ public abstract class PanelViewController { protected void onTrackingStopped(boolean expand) { mTracking = false; - mStatusBar.onTrackingStopped(expand); + mCentralSurfaces.onTrackingStopped(expand); updatePanelExpansionAndVisibility(); } protected void onTrackingStarted() { endClosing(); mTracking = true; - mStatusBar.onTrackingStarted(); + mCentralSurfaces.onTrackingStarted(); notifyExpandingStarted(); updatePanelExpansionAndVisibility(); } @@ -556,7 +557,7 @@ public abstract class PanelViewController { */ private boolean isFalseTouch(float x, float y, @Classifier.InteractionType int interactionType) { - if (!mStatusBar.isFalsingThresholdNeeded()) { + if (!mCentralSurfaces.isFalsingThresholdNeeded()) { return false; } if (mFalsingManager.isClassifierEnabled()) { @@ -921,7 +922,7 @@ public abstract class PanelViewController { mView.getViewTreeObserver().removeOnGlobalLayoutListener(this); return; } - if (mStatusBar.getNotificationShadeWindowView().isVisibleToUser()) { + if (mCentralSurfaces.getNotificationShadeWindowView().isVisibleToUser()) { mView.getViewTreeObserver().removeOnGlobalLayoutListener(this); if (mAnimateAfterExpanding) { notifyExpandingStarted(); @@ -976,11 +977,11 @@ public abstract class PanelViewController { } protected void onUnlockHintFinished() { - mStatusBar.onHintFinished(); + mCentralSurfaces.onHintFinished(); } protected void onUnlockHintStarted() { - mStatusBar.onUnlockHintStarted(); + mCentralSurfaces.onUnlockHintStarted(); } public boolean isUnlockHintRunning() { @@ -1018,7 +1019,7 @@ public abstract class PanelViewController { View[] viewsToAnimate = { mKeyguardBottomArea.getIndicationArea(), - mStatusBar.getAmbientIndicationContainer()}; + mCentralSurfaces.getAmbientIndicationContainer()}; for (View v : viewsToAnimate) { if (v == null) { continue; @@ -1210,7 +1211,7 @@ public abstract class PanelViewController { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: - mStatusBar.userActivity(); + mCentralSurfaces.userActivity(); mAnimatingOnDown = mHeightAnimator != null && !mIsSpringBackAnimation; mMinExpandHeight = 0.0f; mDownTime = SystemClock.uptimeMillis(); @@ -1340,7 +1341,7 @@ public abstract class PanelViewController { onTrackingStarted(); } if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp() - && !mStatusBar.isBouncerShowing()) { + && !mCentralSurfaces.isBouncerShowing()) { startOpening(event); } break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt index 224b2e45bfe5..9da2ef734be8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt @@ -31,6 +31,7 @@ import com.android.systemui.unfold.UNFOLD_STATUS_BAR import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider import com.android.systemui.util.ViewController import com.android.systemui.util.kotlin.getOrNull +import com.android.systemui.util.view.ViewUtil import java.util.Optional @@ -43,6 +44,7 @@ class PhoneStatusBarViewController private constructor( @Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider?, private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?, private val userSwitcherController: StatusBarUserSwitcherController, + private val viewUtil: ViewUtil, touchEventHandler: PhoneStatusBarView.TouchEventHandler, private val configurationController: ConfigurationController ) : ViewController<PhoneStatusBarView>(view) { @@ -118,12 +120,7 @@ class PhoneStatusBarViewController private constructor( * view's range and false otherwise. */ fun touchIsWithinView(x: Float, y: Float): Boolean { - val left = mView.locationOnScreen[0] - val top = mView.locationOnScreen[1] - return left <= x && - x <= left + mView.width && - top <= y && - y <= top + mView.height + return viewUtil.touchIsWithinView(mView, x, y) } class StatusBarViewsCenterProvider : UnfoldMoveFromCenterAnimator.ViewCenterProvider { @@ -163,6 +160,7 @@ class PhoneStatusBarViewController private constructor( @Named(UNFOLD_STATUS_BAR) private val progressProvider: Optional<ScopedUnfoldTransitionProgressProvider>, private val userSwitcherController: StatusBarUserSwitcherController, + private val viewUtil: ViewUtil, private val configurationController: ConfigurationController ) { fun create( @@ -174,6 +172,7 @@ class PhoneStatusBarViewController private constructor( progressProvider.getOrNull(), unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController(), userSwitcherController, + viewUtil, touchEventHandler, configurationController ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt index ea61a8b94e7e..c8174669cc65 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt @@ -37,8 +37,8 @@ class ScreenOffAnimationController @Inject constructor( private val animations: List<ScreenOffAnimation> = listOfNotNull(foldToAodAnimation, unlockedScreenOffAnimation) - fun initialize(statusBar: StatusBar, lightRevealScrim: LightRevealScrim) { - animations.forEach { it.initialize(statusBar, lightRevealScrim) } + fun initialize(centralSurfaces: CentralSurfaces, lightRevealScrim: LightRevealScrim) { + animations.forEach { it.initialize(centralSurfaces, lightRevealScrim) } wakefulnessLifecycle.addObserver(this) } @@ -131,7 +131,7 @@ class ScreenOffAnimationController @Inject constructor( animations.any { it.isKeyguardHideDelayed() } /** - * Return true to make the StatusBar expanded so we can animate [LightRevealScrim] + * Return true to make the status bar expanded so we can animate [LightRevealScrim] */ fun shouldShowLightRevealScrim(): Boolean = animations.any { it.shouldPlayAnimation() } @@ -197,7 +197,7 @@ class ScreenOffAnimationController @Inject constructor( } interface ScreenOffAnimation { - fun initialize(statusBar: StatusBar, lightRevealScrim: LightRevealScrim) {} + fun initialize(centralSurfaces: CentralSurfaces, lightRevealScrim: LightRevealScrim) {} /** * Called when started going to sleep, should return true if the animation will be played 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 8d64041ab76b..a3c795f36d5d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -413,7 +413,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump } if (mKeyguardUpdateMonitor.needsSlowUnlockTransition() && mState == ScrimState.UNLOCKED) { - mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY; + mAnimationDelay = CentralSurfaces.FADE_KEYGUARD_START_DELAY; scheduleUpdate(); } else if (((oldState == ScrimState.AOD || oldState == ScrimState.PULSING) // leaving doze && (!mDozeParameters.getAlwaysOn() || mState == ScrimState.UNLOCKED)) @@ -1255,7 +1255,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump public void setScrimBehindChangeRunnable(Runnable changeRunnable) { // TODO: remove this. This is necessary because of an order-of-operations limitation. - // The fix is to move more of these class into @StatusBarScope + // The fix is to move more of these class into @CentralSurfacesScope if (mScrimBehind == null) { mScrimBehindChangeRunnable = changeRunnable; } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java index bfd625bbd288..902887027667 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -238,7 +238,7 @@ public enum ScrimState { mAnimationDuration = mKeyguardFadingAway ? mKeyguardFadingAwayDuration - : StatusBar.FADE_KEYGUARD_DURATION; + : CentralSurfaces.FADE_KEYGUARD_DURATION; boolean fromAod = previousState == AOD || previousState == PULSING; mAnimateChange = !mLaunchingAffordanceWithPreview && !fromAod; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java index 24bb7f25f2eb..83ee125f84c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java @@ -18,9 +18,9 @@ import com.android.systemui.statusbar.StatusBarState; /** * {@link ShadeController} is an abstraction of the work that used to be hard-coded in - * {@link StatusBar}. The shade itself represents the concept of the status bar window state, and - * can be in multiple states: dozing, locked, showing the bouncer, occluded, etc. All/some of these - * are coordinated with {@link StatusBarKeyguardViewManager} via + * {@link CentralSurfaces}. The shade itself represents the concept of the status bar window state, + * and can be in multiple states: dozing, locked, showing the bouncer, occluded, etc. All/some of + * these are coordinated with {@link StatusBarKeyguardViewManager} via * {@link com.android.systemui.keyguard.KeyguardViewMediator} and others. */ public interface ShadeController { @@ -38,7 +38,7 @@ public interface ShadeController { /** * Collapse the shade animated, showing the bouncer when on {@link StatusBarState#KEYGUARD} or - * dismissing {@link StatusBar} when on {@link StatusBarState#SHADE}. + * dismissing {@link CentralSurfaces} when on {@link StatusBarState#SHADE}. */ void animateCollapsePanels(int flags, boolean force); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java index 53ef97dc317c..cee8b335f380 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java @@ -47,7 +47,7 @@ public class ShadeControllerImpl implements ShadeController { protected final NotificationShadeWindowController mNotificationShadeWindowController; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final int mDisplayId; - protected final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; + protected final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; private final Lazy<AssistManager> mAssistManagerLazy; private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>(); @@ -59,7 +59,7 @@ public class ShadeControllerImpl implements ShadeController { NotificationShadeWindowController notificationShadeWindowController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, WindowManager windowManager, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, Lazy<AssistManager> assistManagerLazy ) { mCommandQueue = commandQueue; @@ -67,15 +67,15 @@ public class ShadeControllerImpl implements ShadeController { mNotificationShadeWindowController = notificationShadeWindowController; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mDisplayId = windowManager.getDefaultDisplay().getDisplayId(); - // TODO: Remove circular reference to StatusBar when possible. - mStatusBarOptionalLazy = statusBarOptionalLazy; + // TODO: Remove circular reference to CentralSurfaces when possible. + mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mAssistManagerLazy = assistManagerLazy; } @Override public void instantExpandNotificationsPanel() { // Make our window larger and the panel expanded. - getStatusBar().makeExpandedVisible(true /* force */); + getCentralSurfaces().makeExpandedVisible(true /* force */); getNotificationPanelViewController().expand(false /* animate */); mCommandQueue.recomputeDisableFlags(mDisplayId, false /* animate */); } @@ -110,7 +110,7 @@ public class ShadeControllerImpl implements ShadeController { } if (SPEW) { Log.d(TAG, "animateCollapse():" - + " mExpandedVisible=" + getStatusBar().isExpandedVisible() + + " mExpandedVisible=" + getCentralSurfaces().isExpandedVisible() + " flags=" + flags); } @@ -124,7 +124,7 @@ public class ShadeControllerImpl implements ShadeController { // release focus immediately to kick off focus change transition mNotificationShadeWindowController.setNotificationShadeFocusable(false); - getStatusBar().getNotificationShadeWindowViewController().cancelExpandHelper(); + getCentralSurfaces().getNotificationShadeWindowViewController().cancelExpandHelper(); getNotificationPanelViewController() .collapsePanel(true /* animate */, delayed, speedUpFactor); } @@ -136,7 +136,7 @@ public class ShadeControllerImpl implements ShadeController { if (!getNotificationPanelViewController().isFullyCollapsed()) { mCommandQueue.animateCollapsePanels( CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); - getStatusBar().visibilityChanged(false); + getCentralSurfaces().visibilityChanged(false); mAssistManagerLazy.get().hideAssist(); } return false; @@ -155,7 +155,7 @@ public class ShadeControllerImpl implements ShadeController { new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { - if (getStatusBar().getNotificationShadeWindowView().isVisibleToUser()) { + if (getCentralSurfaces().getNotificationShadeWindowView().isVisibleToUser()) { getNotificationPanelViewController().removeOnGlobalLayoutListener(this); getNotificationPanelViewController().getView().post(executable); } @@ -185,7 +185,7 @@ public class ShadeControllerImpl implements ShadeController { // close the shade if it was open animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */, true /* delayed */); - getStatusBar().visibilityChanged(false); + getCentralSurfaces().visibilityChanged(false); return true; } else { @@ -201,26 +201,26 @@ public class ShadeControllerImpl implements ShadeController { runPostCollapseRunnables(); } } else if (!getPresenter().isPresenterFullyCollapsed()) { - getStatusBar().instantCollapseNotificationPanel(); - getStatusBar().visibilityChanged(false); + getCentralSurfaces().instantCollapseNotificationPanel(); + getCentralSurfaces().visibilityChanged(false); } else { runPostCollapseRunnables(); } } - private StatusBar getStatusBar() { - return mStatusBarOptionalLazy.get().get(); + private CentralSurfaces getCentralSurfaces() { + return mCentralSurfacesOptionalLazy.get().get(); } private NotificationPresenter getPresenter() { - return getStatusBar().getPresenter(); + return getCentralSurfaces().getPresenter(); } protected NotificationShadeWindowView getNotificationShadeWindowView() { - return getStatusBar().getNotificationShadeWindowView(); + return getCentralSurfaces().getNotificationShadeWindowView(); } private NotificationPanelViewController getNotificationPanelViewController() { - return getStatusBar().getPanelController(); + return getCentralSurfaces().getPanelController(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt index a1be5acdac13..7555356af163 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt @@ -30,7 +30,7 @@ import com.android.systemui.flags.Flags import com.android.systemui.qs.ChipVisibilityListener import com.android.systemui.qs.HeaderPrivacyIconsController import com.android.systemui.qs.carrier.QSCarrierGroupController -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SPLIT_SHADE_BATTERY_CONTROLLER import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SPLIT_SHADE_HEADER import java.io.FileDescriptor @@ -38,7 +38,7 @@ import java.io.PrintWriter import javax.inject.Inject import javax.inject.Named -@StatusBarScope +@CentralSurfacesScope class SplitShadeHeaderController @Inject constructor( @Named(SPLIT_SHADE_HEADER) private val statusBar: View, private val statusBarIconController: StatusBarIconController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java index 6eeae7f29839..50f21691b044 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java @@ -22,14 +22,16 @@ import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.init.NotificationsController; -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.window.StatusBarWindowController; import javax.inject.Inject; -/** Ties the {@link StatusBar} to {@link com.android.systemui.statusbar.policy.HeadsUpManager}. */ -@StatusBarComponent.StatusBarScope +/** + * Ties the {@link CentralSurfaces} to {@link com.android.systemui.statusbar.policy.HeadsUpManager}. + */ +@CentralSurfacesComponent.CentralSurfacesScope public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener { private final NotificationShadeWindowController mNotificationShadeWindowController; private final StatusBarWindowController mStatusBarWindowController; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index 81fb903a87b2..31d9266057da 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -48,6 +48,7 @@ import com.android.systemui.statusbar.StatusIconDisplayable; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState; +import com.android.systemui.util.Assert; import java.util.ArrayList; import java.util.List; @@ -66,6 +67,8 @@ public interface StatusBarIconController { void addIconGroup(IconManager iconManager); /** */ void removeIconGroup(IconManager iconManager); + /** Refresh the state of an IconManager by recreating the views */ + void refreshIconGroup(IconManager iconManager); /** */ void setExternalIcon(String slot); /** */ @@ -243,6 +246,7 @@ public interface StatusBarIconController { protected final int mIconSize; // Whether or not these icons show up in dumpsys protected boolean mShouldLog = false; + private StatusBarIconController mController; // Enables SystemUI demo mode to take effect in this group protected boolean mDemoable = true; @@ -267,13 +271,17 @@ public interface StatusBarIconController { mDemoable = demoable; } + void setController(StatusBarIconController controller) { + mController = controller; + } + public void setBlockList(@Nullable List<String> blockList) { + Assert.isMainThread(); mBlockList.clear(); - if (blockList == null || blockList.isEmpty()) { - return; - } - mBlockList.addAll(blockList); + if (mController != null) { + mController.refreshIconGroup(this); + } } public void setShouldLog(boolean should) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java index c5d3937173e7..623ec5e2b762 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java @@ -100,6 +100,7 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu } } + group.setController(this); mIconGroups.add(group); List<Slot> allSlots = getSlots(); for (int i = 0; i < allSlots.size(); i++) { @@ -115,6 +116,12 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu } } + @Override + public void refreshIconGroup(IconManager iconManager) { + removeIconGroup(iconManager); + addIconGroup(iconManager); + } + private void refreshIconGroups() { for (int i = mIconGroups.size() - 1; i >= 0; --i) { IconManager group = mIconGroups.get(i); @@ -245,7 +252,7 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu /** * Accept a list of CallIndicatorIconStates, and show the call strength icons. - * @param slot StatusBar slot for the call strength icons + * @param slot statusbar slot for the call strength icons * @param states All of the no Calling & SMS icon states */ @Override @@ -272,7 +279,7 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu /** * Accept a list of CallIndicatorIconStates, and show the no calling icons. - * @param slot StatusBar slot for the no calling icons + * @param slot statusbar slot for the no calling icons * @param states All of the no Calling & SMS icon states */ @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index a96ba56be58d..c160c22203a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -124,8 +124,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void onFullyShown() { updateStates(); - mStatusBar.wakeUpIfDozing(SystemClock.uptimeMillis(), - mStatusBar.getBouncerContainer(), "BOUNCER_VISIBLE"); + mCentralSurfaces.wakeUpIfDozing(SystemClock.uptimeMillis(), + mCentralSurfaces.getBouncerContainer(), "BOUNCER_VISIBLE"); } @Override @@ -175,7 +175,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb protected LockPatternUtils mLockPatternUtils; protected ViewMediatorCallback mViewMediatorCallback; - protected StatusBar mStatusBar; + protected CentralSurfaces mCentralSurfaces; private NotificationPanelViewController mNotificationPanelViewController; private BiometricUnlockController mBiometricUnlockController; @@ -277,16 +277,16 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } @Override - public void registerStatusBar(StatusBar statusBar, + public void registerCentralSurfaces(CentralSurfaces centralSurfaces, NotificationPanelViewController notificationPanelViewController, PanelExpansionStateManager panelExpansionStateManager, BiometricUnlockController biometricUnlockController, View notificationContainer, KeyguardBypassController bypassController) { - mStatusBar = statusBar; + mCentralSurfaces = centralSurfaces; mBiometricUnlockController = biometricUnlockController; - ViewGroup container = mStatusBar.getBouncerContainer(); + ViewGroup container = mCentralSurfaces.getBouncerContainer(); mBouncer = mKeyguardBouncerFactory.create(container, mExpansionCallback); mNotificationPanelViewController = notificationPanelViewController; if (panelExpansionStateManager != null) { @@ -354,13 +354,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED && mKeyguardUpdateManager.isUdfpsEnrolled()) { // Don't expand to the bouncer. Instead transition back to the lock screen (see - // StatusBar#showBouncerOrLockScreenIfKeyguard) where the user can use the UDFPS + // CentralSurfaces#showBouncerOrLockScreenIfKeyguard) where the user can use the UDFPS // affordance to enter the device (or swipe up to the input bouncer) return; } else if (bouncerNeedsScrimming()) { mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE); } else if (mShowing) { - if (!isWakeAndUnlocking() && !mStatusBar.isInLaunchTransition()) { + if (!isWakeAndUnlocking() && !mCentralSurfaces.isInLaunchTransition()) { mBouncer.setExpansion(fraction); } if (fraction != KeyguardBouncer.EXPANSION_HIDDEN && tracking @@ -371,7 +371,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } else if (mPulsing && fraction == KeyguardBouncer.EXPANSION_VISIBLE) { // Panel expanded while pulsing but didn't translate the bouncer (because we are // unlocked.) Let's simply wake-up to dismiss the lock screen. - mStatusBar.wakeUpIfDozing(SystemClock.uptimeMillis(), mStatusBar.getBouncerContainer(), + mCentralSurfaces.wakeUpIfDozing( + SystemClock.uptimeMillis(), + mCentralSurfaces.getBouncerContainer(), "BOUNCER_VISIBLE"); } } @@ -408,10 +410,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) { if (mBouncer.needsFullscreenBouncer() && !mDozing) { // The keyguard might be showing (already). So we need to hide it. - mStatusBar.hideKeyguard(); + mCentralSurfaces.hideKeyguard(); mBouncer.show(true /* resetSecuritySelection */); } else { - mStatusBar.showKeyguard(); + mCentralSurfaces.showKeyguard(); if (hideBouncerWhenShowing) { hideBouncer(false /* destroyView */); mBouncer.prepare(); @@ -540,7 +542,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mNotificationPanelViewController.resetViews(/* animate= */ true); // Hide bouncer and quick-quick settings. if (mOccluded && !mDozing) { - mStatusBar.hideKeyguard(); + mCentralSurfaces.hideKeyguard(); if (hideBouncerWhenShowing || mBouncer.needsFullscreenBouncer()) { hideBouncer(false /* destroyView */); } @@ -570,15 +572,15 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mBypassController.setAltBouncerShowing(isShowingAlternateAuth()); if (updateScrim) { - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); } } @Override public void onStartedWakingUp() { - mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() + mCentralSurfaces.getNotificationShadeWindowView().getWindowInsetsController() .setAnimationsDisabled(false); - NavigationBarView navBarView = mStatusBar.getNavigationBarView(); + NavigationBarView navBarView = mCentralSurfaces.getNavigationBarView(); if (navBarView != null) { navBarView.forEachView(view -> view.animate() @@ -590,9 +592,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void onStartedGoingToSleep() { - mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() + mCentralSurfaces.getNotificationShadeWindowView().getWindowInsetsController() .setAnimationsDisabled(true); - NavigationBarView navBarView = mStatusBar.getNavigationBarView(); + NavigationBarView navBarView = mCentralSurfaces.getNavigationBarView(); if (navBarView != null) { navBarView.forEachView(view -> view.animate() @@ -628,7 +630,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } /** - * If {@link StatusBar} is pulsing. + * If {@link CentralSurfaces} is pulsing. */ public void setPulsing(boolean pulsing) { if (mPulsing != pulsing) { @@ -649,13 +651,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void setOccluded(boolean occluded, boolean animate) { - mStatusBar.setOccluded(occluded); + mCentralSurfaces.setOccluded(occluded); if (occluded && !mOccluded && mShowing) { SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__OCCLUDED); - if (mStatusBar.isInLaunchTransition()) { + if (mCentralSurfaces.isInLaunchTransition()) { setOccludedAndUpdateStates(true); - mStatusBar.fadeKeyguardAfterLaunchTransition(null /* beforeFading */, + mCentralSurfaces.fadeKeyguardAfterLaunchTransition(null /* beforeFading */, new Runnable() { @Override public void run() { @@ -666,7 +668,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb return; } - if (mStatusBar.isLaunchingActivityOverLockscreen()) { + if (mCentralSurfaces.isLaunchingActivityOverLockscreen()) { setOccludedAndUpdateStates(true); // When isLaunchingActivityOverLockscreen() is true, we know for sure that the post @@ -695,7 +697,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb reset(isOccluding /* hideBouncerWhenShowing*/); } if (animate && !occluded && mShowing && !mBouncer.isShowing()) { - mStatusBar.animateKeyguardUnoccluding(); + mCentralSurfaces.animateKeyguardUnoccluding(); } } @@ -712,7 +714,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void startPreHideAnimation(Runnable finishRunnable) { if (mBouncer.isShowing()) { mBouncer.startPreHideAnimation(finishRunnable); - mStatusBar.onBouncerPreHideAnimation(); + mCentralSurfaces.onBouncerPreHideAnimation(); // We update the state (which will show the keyguard) only if an animation will run on // the keyguard. If there is no animation, we wait before updating the state so that we @@ -745,11 +747,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb long uptimeMillis = SystemClock.uptimeMillis(); long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis); - if (mStatusBar.isInLaunchTransition() + if (mCentralSurfaces.isInLaunchTransition() || mKeyguardStateController.isFlingingToDismissKeyguard()) { final boolean wasFlingingToDismissKeyguard = mKeyguardStateController.isFlingingToDismissKeyguard(); - mStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() { + mCentralSurfaces.fadeKeyguardAfterLaunchTransition(new Runnable() { @Override public void run() { mNotificationShadeWindowController.setKeyguardShowing(false); @@ -760,11 +762,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb }, new Runnable() { @Override public void run() { - mStatusBar.hideKeyguard(); + mCentralSurfaces.hideKeyguard(); mNotificationShadeWindowController.setKeyguardFadingAway(false); if (wasFlingingToDismissKeyguard) { - mStatusBar.finishKeyguardFadingAway(); + mCentralSurfaces.finishKeyguardFadingAway(); } mViewMediatorCallback.keyguardGone(); @@ -783,7 +785,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb delay = 0; fadeoutDuration = 240; } - mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration, needsFading); + mCentralSurfaces.setKeyguardFadingAway(startTime, delay, fadeoutDuration, needsFading); mBiometricUnlockController.startKeyguardFadingAway(); hideBouncer(true /* destroyView */); if (wakeUnlockPulsing) { @@ -793,11 +795,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mNotificationContainer, fadeoutDuration, () -> { - mStatusBar.hideKeyguard(); + mCentralSurfaces.hideKeyguard(); onKeyguardFadedAway(); }); } else { - mStatusBar.fadeKeyguardWhilePulsing(); + mCentralSurfaces.fadeKeyguardWhilePulsing(); } wakeAndUnlockDejank(); } else { @@ -810,20 +812,20 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mNotificationContainer, fadeoutDuration, () -> { - mStatusBar.hideKeyguard(); + mCentralSurfaces.hideKeyguard(); }); } else { - mStatusBar.hideKeyguard(); + mCentralSurfaces.hideKeyguard(); } // hide() will happen asynchronously and might arrive after the scrims // were already hidden, this means that the transition callback won't // be triggered anymore and StatusBarWindowController will be forever in // the fadingAway state. - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); wakeAndUnlockDejank(); } else { - mStatusBar.hideKeyguard(); - mStatusBar.finishKeyguardFadingAway(); + mCentralSurfaces.hideKeyguard(); + mCentralSurfaces.finishKeyguardFadingAway(); mBiometricUnlockController.finishKeyguardFadingAway(); } } @@ -866,7 +868,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mNotificationContainer.postDelayed(() -> mNotificationShadeWindowController .setKeyguardFadingAway(false), 100); ViewGroupFadeHelper.reset(mNotificationPanelViewController.getView()); - mStatusBar.finishKeyguardFadingAway(); + mCentralSurfaces.finishKeyguardFadingAway(); mBiometricUnlockController.finishKeyguardFadingAway(); WindowManagerGlobal.getInstance().trimMemory( ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); @@ -897,7 +899,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void dismissAndCollapse() { - mStatusBar.executeRunnableDismissingKeyguard(null, null, true, false, true); + mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, true, false, true); } /** @@ -922,7 +924,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb */ public boolean onBackPressed(boolean hideImmediately) { if (mBouncer.isShowing()) { - mStatusBar.endAffordanceLaunch(); + mCentralSurfaces.endAffordanceLaunch(); // The second condition is for SIM card locked bouncer if (mBouncer.isScrimmed() && !mBouncer.needsFullscreenBouncer()) { hideBouncer(false); @@ -978,11 +980,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private Runnable mMakeNavigationBarVisibleRunnable = new Runnable() { @Override public void run() { - NavigationBarView view = mStatusBar.getNavigationBarView(); + NavigationBarView view = mCentralSurfaces.getNavigationBarView(); if (view != null) { view.setVisibility(View.VISIBLE); } - mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() + mCentralSurfaces.getNotificationShadeWindowView().getWindowInsetsController() .show(navigationBars()); } }; @@ -1013,7 +1015,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) { mNotificationShadeWindowController.setBouncerShowing(bouncerShowing); - mStatusBar.setBouncerShowing(bouncerShowing); + mCentralSurfaces.setBouncerShowing(bouncerShowing); } if (occluded != mLastOccluded || mFirstUpdate) { @@ -1040,11 +1042,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mLastBiometricMode = mBiometricUnlockController.getMode(); mLastGesturalNav = mGesturalNav; mLastIsDocked = mIsDocked; - mStatusBar.onKeyguardViewManagerStatesUpdated(); + mCentralSurfaces.onKeyguardViewManagerStatesUpdated(); } private View getCurrentNavBarView() { - final NavigationBarView navBarView = mStatusBar.getNavigationBarView(); + final NavigationBarView navBarView = mCentralSurfaces.getNavigationBarView(); return navBarView != null ? navBarView.getCurrentView() : null; } @@ -1052,7 +1054,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb * Updates the visibility of the nav bar window (which will cause insets changes). */ protected void updateNavigationBarVisibility(boolean navBarVisible) { - if (mStatusBar.getNavigationBarView() != null) { + if (mCentralSurfaces.getNavigationBarView() != null) { if (navBarVisible) { long delay = getNavBarShowDelay(); if (delay == 0) { @@ -1063,7 +1065,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } } else { mNotificationContainer.removeCallbacks(mMakeNavigationBarVisibleRunnable); - mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() + mCentralSurfaces.getNotificationShadeWindowView().getWindowInsetsController() .hide(navigationBars()); } } @@ -1120,7 +1122,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public boolean shouldDisableWindowAnimationsForUnlock() { - return mStatusBar.isInLaunchTransition(); + return mCentralSurfaces.isInLaunchTransition(); } @Override @@ -1139,7 +1141,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void keyguardGoingAway() { - mStatusBar.keyguardGoingAway(); + mCentralSurfaces.keyguardGoingAway(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt index 09fca100749c..56b6dfc42ee3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt @@ -10,34 +10,34 @@ import com.android.systemui.animation.LaunchAnimator */ class StatusBarLaunchAnimatorController( private val delegate: ActivityLaunchAnimator.Controller, - private val statusBar: StatusBar, + private val centralSurfaces: CentralSurfaces, private val isLaunchForActivity: Boolean = true ) : ActivityLaunchAnimator.Controller by delegate { // Always sync the opening window with the shade, given that we draw a hole punch in the shade // of the same size and position as the opening app to make it visible. override val openingWindowSyncView: View? - get() = statusBar.notificationShadeWindowView + get() = centralSurfaces.notificationShadeWindowView override fun onIntentStarted(willAnimate: Boolean) { delegate.onIntentStarted(willAnimate) if (!willAnimate) { - statusBar.collapsePanelOnMainThread() + centralSurfaces.collapsePanelOnMainThread() } } override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { delegate.onLaunchAnimationStart(isExpandingFullyAbove) - statusBar.notificationPanelViewController.setIsLaunchAnimationRunning(true) + centralSurfaces.notificationPanelViewController.setIsLaunchAnimationRunning(true) if (!isExpandingFullyAbove) { - statusBar.collapsePanelWithDuration( + centralSurfaces.collapsePanelWithDuration( ActivityLaunchAnimator.TIMINGS.totalDuration.toInt()) } } override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) { delegate.onLaunchAnimationEnd(isExpandingFullyAbove) - statusBar.notificationPanelViewController.setIsLaunchAnimationRunning(false) - statusBar.onLaunchAnimationEnd(isExpandingFullyAbove) + centralSurfaces.notificationPanelViewController.setIsLaunchAnimationRunning(false) + centralSurfaces.onLaunchAnimationEnd(isExpandingFullyAbove) } override fun onLaunchAnimationProgress( @@ -46,11 +46,11 @@ class StatusBarLaunchAnimatorController( linearProgress: Float ) { delegate.onLaunchAnimationProgress(state, progress, linearProgress) - statusBar.notificationPanelViewController.applyLaunchAnimationProgress(linearProgress) + centralSurfaces.notificationPanelViewController.applyLaunchAnimationProgress(linearProgress) } override fun onLaunchAnimationCancelled() { delegate.onLaunchAnimationCancelled() - statusBar.onLaunchAnimationCancelled(isLaunchForActivity) + centralSurfaces.onLaunchAnimationCancelled(isLaunchForActivity) } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index ff86d74a86eb..edbddbb3c3e7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -18,7 +18,7 @@ package com.android.systemui.statusbar.phone; import static android.service.notification.NotificationListenerService.REASON_CLICK; -import static com.android.systemui.statusbar.phone.StatusBar.getActivityOptions; +import static com.android.systemui.statusbar.phone.CentralSurfaces.getActivityOptions; import android.app.ActivityManager; import android.app.KeyguardManager; @@ -51,9 +51,6 @@ import com.android.systemui.ActivityIntentHelper; import com.android.systemui.EventLogTags; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.assist.AssistManager; -import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; @@ -75,6 +72,7 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowDragController; import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback; +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.policy.HeadsUpUtil; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.wmshell.BubblesManager; @@ -89,7 +87,8 @@ import dagger.Lazy; /** * Status bar implementation of {@link NotificationActivityStarter}. */ -public class StatusBarNotificationActivityStarter implements NotificationActivityStarter { +@CentralSurfacesComponent.CentralSurfacesScope +class StatusBarNotificationActivityStarter implements NotificationActivityStarter { private final Context mContext; @@ -123,7 +122,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final MetricsLogger mMetricsLogger; private final StatusBarNotificationActivityStarterLogger mLogger; - private final StatusBar mStatusBar; + private final CentralSurfaces mCentralSurfaces; private final NotificationPresenter mPresenter; private final NotificationPanelViewController mNotificationPanel; private final ActivityLaunchAnimator mActivityLaunchAnimator; @@ -132,7 +131,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private boolean mIsCollapsingToShowActivityOverLockscreen; - private StatusBarNotificationActivityStarter( + @Inject + StatusBarNotificationActivityStarter( Context context, CommandQueue commandQueue, Handler mainThreadHandler, @@ -162,7 +162,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit MetricsLogger metricsLogger, StatusBarNotificationActivityStarterLogger logger, OnUserInteractionCallback onUserInteractionCallback, - StatusBar statusBar, + CentralSurfaces centralSurfaces, NotificationPresenter presenter, NotificationPanelViewController panel, ActivityLaunchAnimator activityLaunchAnimator, @@ -199,7 +199,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mOnUserInteractionCallback = onUserInteractionCallback; // TODO: use KeyguardStateController#isOccluded to remove this dependency - mStatusBar = statusBar; + mCentralSurfaces = centralSurfaces; mPresenter = presenter; mNotificationPanel = panel; mActivityLaunchAnimator = activityLaunchAnimator; @@ -259,7 +259,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit && mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(), mLockscreenUserManager.getCurrentUserId()); final boolean animate = !willLaunchResolverActivity - && mStatusBar.shouldAnimateLaunch(isActivityIntent); + && mCentralSurfaces.shouldAnimateLaunch(isActivityIntent); boolean showOverLockscreen = mKeyguardStateController.isShowing() && intent != null && mActivityIntentHelper.wouldShowOverLockscreen(intent.getIntent(), mLockscreenUserManager.getCurrentUserId()); @@ -300,7 +300,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mShadeController.addPostCollapseAction(runnable); mShadeController.collapsePanel(true /* animate */); } else if (mKeyguardStateController.isShowing() - && mStatusBar.isOccluded()) { + && mCentralSurfaces.isOccluded()) { mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable); mShadeController.collapsePanel(); } else { @@ -475,7 +475,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit try { ActivityLaunchAnimator.Controller animationController = new StatusBarLaunchAnimatorController( - mNotificationAnimationProvider.getAnimatorController(row), mStatusBar, + mNotificationAnimationProvider.getAnimatorController(row), + mCentralSurfaces, isActivityIntent); mActivityLaunchAnimator.startPendingIntentWithAnimation(animationController, @@ -483,11 +484,11 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit long eventTime = row.getAndResetLastActionUpTime(); Bundle options = eventTime > 0 ? getActivityOptions( - mStatusBar.getDisplayId(), + mCentralSurfaces.getDisplayId(), adapter, mKeyguardStateController.isShowing(), eventTime) - : getActivityOptions(mStatusBar.getDisplayId(), adapter); + : getActivityOptions(mCentralSurfaces.getDisplayId(), adapter); return intent.sendAndReturnResult(mContext, 0, fillInIntent, null, null, null, options); }); @@ -502,7 +503,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit @Override public void startNotificationGutsIntent(final Intent intent, final int appUid, ExpandableNotificationRow row) { - boolean animate = mStatusBar.shouldAnimateLaunch(true /* isActivityIntent */); + boolean animate = mCentralSurfaces.shouldAnimateLaunch(true /* isActivityIntent */); ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() { @Override public boolean onDismiss() { @@ -510,14 +511,14 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit ActivityLaunchAnimator.Controller animationController = new StatusBarLaunchAnimatorController( mNotificationAnimationProvider.getAnimatorController(row), - mStatusBar, true /* isActivityIntent */); + mCentralSurfaces, true /* isActivityIntent */); mActivityLaunchAnimator.startIntentWithAnimation( animationController, animate, intent.getPackage(), (adapter) -> TaskStackBuilder.create(mContext) .addNextIntentWithParentStack(intent) .startActivities(getActivityOptions( - mStatusBar.getDisplayId(), + mCentralSurfaces.getDisplayId(), adapter), new UserHandle(UserHandle.getUserId(appUid)))); }); @@ -535,7 +536,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit @Override public void startHistoryIntent(View view, boolean showHistory) { - boolean animate = mStatusBar.shouldAnimateLaunch(true /* isActivityIntent */); + boolean animate = mCentralSurfaces.shouldAnimateLaunch(true /* isActivityIntent */); ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() { @Override public boolean onDismiss() { @@ -555,13 +556,14 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit ); ActivityLaunchAnimator.Controller animationController = viewController == null ? null - : new StatusBarLaunchAnimatorController(viewController, mStatusBar, + : new StatusBarLaunchAnimatorController(viewController, + mCentralSurfaces, true /* isActivityIntent */); mActivityLaunchAnimator.startIntentWithAnimation(animationController, animate, intent.getPackage(), (adapter) -> tsb.startActivities( - getActivityOptions(mStatusBar.getDisplayId(), adapter), + getActivityOptions(mCentralSurfaces.getDisplayId(), adapter), UserHandle.CURRENT)); }); return true; @@ -615,7 +617,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit try { EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION, entry.getKey()); - mStatusBar.wakeUpForFullScreenIntent(); + mCentralSurfaces.wakeUpForFullScreenIntent(); fullscreenIntent.send(); entry.notifyFullScreenIntentLaunched(); mMetricsLogger.count("note_fullscreen", 1); @@ -657,180 +659,4 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit return entry.shouldSuppressFullScreenIntent(); } - - // --------------------- NotificationEntryManager/NotifPipeline methods ------------------------ - - /** - * Public builder for {@link StatusBarNotificationActivityStarter}. - */ - @SysUISingleton - public static class Builder { - private final Context mContext; - private final CommandQueue mCommandQueue; - private final Handler mMainThreadHandler; - - private final Executor mUiBgExecutor; - private final NotificationEntryManager mEntryManager; - private final NotifPipeline mNotifPipeline; - private final NotificationVisibilityProvider mVisibilityProvider; - private final HeadsUpManagerPhone mHeadsUpManager; - private final ActivityStarter mActivityStarter; - private final NotificationClickNotifier mClickNotifier; - private final StatusBarStateController mStatusBarStateController; - private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; - private final KeyguardManager mKeyguardManager; - private final IDreamManager mDreamManager; - private final Optional<BubblesManager> mBubblesManagerOptional; - private final Lazy<AssistManager> mAssistManagerLazy; - private final NotificationRemoteInputManager mRemoteInputManager; - private final GroupMembershipManager mGroupMembershipManager; - private final NotificationLockscreenUserManager mLockscreenUserManager; - private final ShadeController mShadeController; - private final KeyguardStateController mKeyguardStateController; - private final NotificationInterruptStateProvider mNotificationInterruptStateProvider; - private final LockPatternUtils mLockPatternUtils; - private final StatusBarRemoteInputCallback mRemoteInputCallback; - private final ActivityIntentHelper mActivityIntentHelper;; - private final MetricsLogger mMetricsLogger; - private final StatusBarNotificationActivityStarterLogger mLogger; - private final OnUserInteractionCallback mOnUserInteractionCallback; - private final NotifPipelineFlags mNotifPipelineFlags; - private StatusBar mStatusBar; - private NotificationPresenter mNotificationPresenter; - private NotificationPanelViewController mNotificationPanelViewController; - private ActivityLaunchAnimator mActivityLaunchAnimator; - private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider; - - @Inject - public Builder( - Context context, - CommandQueue commandQueue, - @Main Handler mainThreadHandler, - @UiBackground Executor uiBgExecutor, - NotificationEntryManager entryManager, - NotifPipeline notifPipeline, - NotificationVisibilityProvider visibilityProvider, - HeadsUpManagerPhone headsUpManager, - ActivityStarter activityStarter, - NotificationClickNotifier clickNotifier, - StatusBarStateController statusBarStateController, - StatusBarKeyguardViewManager statusBarKeyguardViewManager, - KeyguardManager keyguardManager, - IDreamManager dreamManager, - Optional<BubblesManager> bubblesManager, - Lazy<AssistManager> assistManagerLazy, - NotificationRemoteInputManager remoteInputManager, - GroupMembershipManager groupMembershipManager, - NotificationLockscreenUserManager lockscreenUserManager, - ShadeController shadeController, - KeyguardStateController keyguardStateController, - NotificationInterruptStateProvider notificationInterruptStateProvider, - LockPatternUtils lockPatternUtils, - StatusBarRemoteInputCallback remoteInputCallback, - ActivityIntentHelper activityIntentHelper, - NotifPipelineFlags notifPipelineFlags, - MetricsLogger metricsLogger, - StatusBarNotificationActivityStarterLogger logger, - OnUserInteractionCallback onUserInteractionCallback) { - - mContext = context; - mCommandQueue = commandQueue; - mMainThreadHandler = mainThreadHandler; - mUiBgExecutor = uiBgExecutor; - mEntryManager = entryManager; - mNotifPipeline = notifPipeline; - mVisibilityProvider = visibilityProvider; - mHeadsUpManager = headsUpManager; - mActivityStarter = activityStarter; - mClickNotifier = clickNotifier; - mStatusBarStateController = statusBarStateController; - mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; - mKeyguardManager = keyguardManager; - mDreamManager = dreamManager; - mBubblesManagerOptional = bubblesManager; - mAssistManagerLazy = assistManagerLazy; - mRemoteInputManager = remoteInputManager; - mGroupMembershipManager = groupMembershipManager; - mLockscreenUserManager = lockscreenUserManager; - mShadeController = shadeController; - mKeyguardStateController = keyguardStateController; - mNotificationInterruptStateProvider = notificationInterruptStateProvider; - mLockPatternUtils = lockPatternUtils; - mRemoteInputCallback = remoteInputCallback; - mActivityIntentHelper = activityIntentHelper; - mNotifPipelineFlags = notifPipelineFlags; - mMetricsLogger = metricsLogger; - mLogger = logger; - mOnUserInteractionCallback = onUserInteractionCallback; - } - - /** Sets the status bar to use as {@link StatusBar}. */ - public Builder setStatusBar(StatusBar statusBar) { - mStatusBar = statusBar; - return this; - } - - public Builder setNotificationPresenter(NotificationPresenter notificationPresenter) { - mNotificationPresenter = notificationPresenter; - return this; - } - - /** Set the ActivityLaunchAnimator. */ - public Builder setActivityLaunchAnimator(ActivityLaunchAnimator activityLaunchAnimator) { - mActivityLaunchAnimator = activityLaunchAnimator; - return this; - } - - /** Set the NotificationLaunchAnimatorControllerProvider. */ - public Builder setNotificationAnimatorControllerProvider( - NotificationLaunchAnimatorControllerProvider notificationAnimationProvider) { - mNotificationAnimationProvider = notificationAnimationProvider; - return this; - } - - /** Set the NotificationPanelViewController. */ - public Builder setNotificationPanelViewController( - NotificationPanelViewController notificationPanelViewController) { - mNotificationPanelViewController = notificationPanelViewController; - return this; - } - - public StatusBarNotificationActivityStarter build() { - return new StatusBarNotificationActivityStarter( - mContext, - mCommandQueue, - mMainThreadHandler, - mUiBgExecutor, - mEntryManager, - mNotifPipeline, - mVisibilityProvider, - mHeadsUpManager, - mActivityStarter, - mClickNotifier, - mStatusBarStateController, - mStatusBarKeyguardViewManager, - mKeyguardManager, - mDreamManager, - mBubblesManagerOptional, - mAssistManagerLazy, - mRemoteInputManager, - mGroupMembershipManager, - mLockscreenUserManager, - mShadeController, - mKeyguardStateController, - mNotificationInterruptStateProvider, - mLockPatternUtils, - mRemoteInputCallback, - mActivityIntentHelper, - mNotifPipelineFlags, - mMetricsLogger, - mLogger, - mOnUserInteractionCallback, - mStatusBar, - mNotificationPresenter, - mNotificationPanelViewController, - mActivityLaunchAnimator, - mNotificationAnimationProvider); - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterModule.java new file mode 100644 index 000000000000..caa149e61921 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterModule.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import com.android.systemui.statusbar.notification.NotificationActivityStarter; + +import dagger.Binds; +import dagger.Module; + +@Module +public abstract class StatusBarNotificationActivityStarterModule { + @Binds + abstract NotificationActivityStarter bindActivityStarter( + StatusBarNotificationActivityStarter impl); +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index c8e1cdc75242..aa061d74f6c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -14,9 +14,9 @@ package com.android.systemui.statusbar.phone; -import static com.android.systemui.statusbar.phone.StatusBar.CLOSE_PANEL_WHEN_EMPTIED; -import static com.android.systemui.statusbar.phone.StatusBar.DEBUG; -import static com.android.systemui.statusbar.phone.StatusBar.MULTIUSER_DEBUG; +import static com.android.systemui.statusbar.phone.CentralSurfaces.CLOSE_PANEL_WHEN_EMPTIED; +import static com.android.systemui.statusbar.phone.CentralSurfaces.DEBUG; +import static com.android.systemui.statusbar.phone.CentralSurfaces.MULTIUSER_DEBUG; import android.app.KeyguardManager; import android.content.Context; @@ -68,20 +68,25 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener; import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import java.util.List; -public class StatusBarNotificationPresenter implements NotificationPresenter, +import javax.inject.Inject; + +@CentralSurfacesComponent.CentralSurfacesScope +class StatusBarNotificationPresenter implements NotificationPresenter, ConfigurationController.ConfigurationListener, NotificationRowBinderImpl.BindRowCallback, CommandQueue.Callbacks { private static final String TAG = "StatusBarNotificationPresenter"; - private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class); + private final ActivityStarter mActivityStarter; private final KeyguardStateController mKeyguardStateController; private final NotificationViewHierarchyManager mViewHierarchyManager; private final NotificationLockscreenUserManager mLockscreenUserManager; @@ -99,7 +104,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, private final DozeScrimController mDozeScrimController; private final ScrimController mScrimController; private final KeyguardIndicationController mKeyguardIndicationController; - private final StatusBar mStatusBar; + private final CentralSurfaces mCentralSurfaces; private final ShadeController mShadeController; private final LockscreenShadeTransitionController mShadeTransitionController; private final CommandQueue mCommandQueue; @@ -110,16 +115,19 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, private final NotifPipelineFlags mNotifPipelineFlags; private final IStatusBarService mBarService; private final DynamicPrivacyController mDynamicPrivacyController; + private final NotificationListContainer mNotifListContainer; private boolean mReinflateNotificationsOnUserSwitched; private boolean mDispatchUiModeChangeOnUserSwitched; private TextView mNotificationPanelDebugText; protected boolean mVrMode; - public StatusBarNotificationPresenter(Context context, + @Inject + StatusBarNotificationPresenter(Context context, NotificationPanelViewController panel, HeadsUpManagerPhone headsUp, NotificationShadeWindowView statusBarWindow, + ActivityStarter activityStarter, NotificationStackScrollLayoutController stackScrollerController, DozeScrimController dozeScrimController, ScrimController scrimController, @@ -127,7 +135,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, DynamicPrivacyController dynamicPrivacyController, KeyguardStateController keyguardStateController, KeyguardIndicationController keyguardIndicationController, - StatusBar statusBar, + CentralSurfaces centralSurfaces, ShadeController shadeController, LockscreenShadeTransitionController shadeTransitionController, CommandQueue commandQueue, @@ -144,14 +152,17 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, NotificationInterruptStateProvider notificationInterruptStateProvider, NotificationRemoteInputManager remoteInputManager, ConfigurationController configurationController, - NotifPipelineFlags notifPipelineFlags) { + NotifPipelineFlags notifPipelineFlags, + NotificationRemoteInputManager.Callback remoteInputManagerCallback, + NotificationListContainer notificationListContainer) { + mActivityStarter = activityStarter; mKeyguardStateController = keyguardStateController; mNotificationPanel = panel; mHeadsUpManager = headsUp; mDynamicPrivacyController = dynamicPrivacyController; mKeyguardIndicationController = keyguardIndicationController; // TODO: use KeyguardStateController#isOccluded to remove this dependency - mStatusBar = statusBar; + mCentralSurfaces = centralSurfaces; mShadeController = shadeController; mShadeTransitionController = shadeTransitionController; mCommandQueue = commandQueue; @@ -175,6 +186,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, mKeyguardManager = context.getSystemService(KeyguardManager.class); mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + mNotifListContainer = notificationListContainer; IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService( Context.VR_SERVICE)); @@ -186,14 +198,14 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } } remoteInputManager.setUpWithCallback( - Dependency.get(NotificationRemoteInputManager.Callback.class), + remoteInputManagerCallback, mNotificationPanel.createRemoteInputDelegate()); initController.addPostInitTask(() -> { mKeyguardIndicationController.init(); mViewHierarchyManager.setUpWithPresenter(this, stackScrollerController.getNotifStackController(), - stackScrollerController.getNotificationListContainer()); + mNotifListContainer); mNotifShadeEventSource.setShadeEmptiedCallback(this::maybeClosePanelForShadeEmptied); mNotifShadeEventSource.setNotifRemovedByUserCallback(this::maybeEndAmbientPulse); if (!mNotifPipelineFlags.isNewPipelineEnabled()) { @@ -206,9 +218,8 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, notificationInterruptStateProvider.addSuppressor(mInterruptSuppressor); mLockscreenUserManager.setUpWithPresenter(this); mMediaManager.setUpWithPresenter(this); - mGutsManager.setUpWithPresenter(this, - stackScrollerController.getNotificationListContainer(), mCheckSaveListener, - mOnSettingsClickListener); + mGutsManager.setUpWithPresenter( + this, mNotifListContainer, mCheckSaveListener, mOnSettingsClickListener); // ForegroundServiceNotificationListener adds its listener in its constructor // but we need to request it here in order for it to be instantiated. // TODO: figure out how to do this correctly once Dependency.get() is gone. @@ -341,7 +352,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, updateNotificationViews("user switched"); } mMediaManager.clearCurrentMediaNotification(); - mStatusBar.setLockscreenUser(newUserId); + mCentralSurfaces.setLockscreenUser(newUserId); updateMediaMetaData(true, false); } @@ -395,7 +406,8 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, public void onExpandClicked(NotificationEntry clickedEntry, View clickedView, boolean nowExpanded) { mHeadsUpManager.setExpanded(clickedEntry, nowExpanded); - mStatusBar.wakeUpIfDozing(SystemClock.uptimeMillis(), clickedView, "NOTIFICATION_CLICK"); + mCentralSurfaces.wakeUpIfDozing( + SystemClock.uptimeMillis(), clickedView, "NOTIFICATION_CLICK"); if (nowExpanded) { if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) { mShadeTransitionController.goToLockedShade(clickedEntry.getRow()); @@ -463,7 +475,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, @Override public boolean suppressAwakeHeadsUp(NotificationEntry entry) { final StatusBarNotification sbn = entry.getSbn(); - if (mStatusBar.isOccluded()) { + if (mCentralSurfaces.isOccluded()) { boolean devicePublic = mLockscreenUserManager .isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId()); boolean userPublic = devicePublic @@ -486,7 +498,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, // we don't allow head-up on the lockscreen (unless there's a // "showWhenLocked" activity currently showing) if // the potential HUN has a fullscreen intent - if (mKeyguardStateController.isShowing() && !mStatusBar.isOccluded()) { + if (mKeyguardStateController.isShowing() && !mCentralSurfaces.isOccluded()) { if (DEBUG) { Log.d(TAG, "No heads up: entry has fullscreen intent on lockscreen " + sbn.getKey()); @@ -511,7 +523,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, @Override public boolean suppressInterruptions(NotificationEntry entry) { - return mStatusBar.areNotificationAlertsDisabled(); + return mCentralSurfaces.areNotificationAlertsDisabled(); } }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterModule.java new file mode 100644 index 000000000000..26c483ce18fa --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterModule.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import com.android.systemui.statusbar.NotificationPresenter; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; + +import dagger.Binds; +import dagger.Module; + +@Module +public abstract class StatusBarNotificationPresenterModule { + @Binds + abstract NotificationPresenter bindPresenter(StatusBarNotificationPresenter impl); + + @Binds + abstract NotificationRowBinderImpl.BindRowCallback bindBindRowCallback( + StatusBarNotificationPresenter impl); +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java index b0206f073011..ee242a4b1b75 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java @@ -44,7 +44,7 @@ import java.util.Objects; import javax.inject.Inject; -/** Controls the signal policies for icons shown in the StatusBar. **/ +/** Controls the signal policies for icons shown in the statusbar. **/ @SysUISingleton public class StatusBarSignalPolicy implements SignalCallback, SecurityController.SecurityControllerCallback, Tunable { @@ -449,7 +449,7 @@ public class StatusBarSignalPolicy implements SignalCallback, } /** - * Stores the StatusBar state for no Calling & SMS. + * Stores the statusbar state for no Calling & SMS. */ public static class CallIndicatorIconState { public boolean isNoCalling; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java index b742394b18a5..95667cc0b972 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java @@ -59,7 +59,7 @@ public final class StatusBarTouchableRegionManager implements Dumpable { private boolean mIsStatusBarExpanded = false; private boolean mShouldAdjustInsets = false; - private StatusBar mStatusBar; + private CentralSurfaces mCentralSurfaces; private View mNotificationShadeWindowView; private View mNotificationPanelView; private boolean mForceCollapsedUntilLayout = false; @@ -119,9 +119,9 @@ public final class StatusBarTouchableRegionManager implements Dumpable { } protected void setup( - @NonNull StatusBar statusBar, + @NonNull CentralSurfaces centralSurfaces, @NonNull View notificationShadeWindowView) { - mStatusBar = statusBar; + mCentralSurfaces = centralSurfaces; mNotificationShadeWindowView = notificationShadeWindowView; mNotificationPanelView = mNotificationShadeWindowView.findViewById(R.id.notification_panel); } @@ -246,7 +246,7 @@ public final class StatusBarTouchableRegionManager implements Dumpable { new OnComputeInternalInsetsListener() { @Override public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) { - if (mIsStatusBarExpanded || mStatusBar.isBouncerShowing()) { + if (mIsStatusBarExpanded || mCentralSurfaces.isBouncerShowing()) { // The touchable region is always the full area when expanded return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainViewController.java index 26ba31c6f526..582afb1a23ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainViewController.java @@ -20,7 +20,7 @@ import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TIMEOUT_M import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; import com.android.systemui.util.ViewController; @@ -32,7 +32,7 @@ import javax.inject.Named; /** * Controller for {@link TapAgainView}. */ -@StatusBarComponent.StatusBarScope +@CentralSurfacesComponent.CentralSurfacesScope public class TapAgainViewController extends ViewController<TapAgainView> { private final DelayableExecutor mDelayableExecutor; private final ConfigurationController mConfigurationController; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt index 0abe8e489638..8b0eaec5dcf4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt @@ -60,14 +60,21 @@ class UnlockedScreenOffAnimationController @Inject constructor( private val handler: Handler = Handler() ) : WakefulnessLifecycle.Observer, ScreenOffAnimation { - private lateinit var statusBar: StatusBar + private lateinit var mCentralSurfaces: CentralSurfaces + + /** + * Whether or not [initialize] has been called to provide us with the StatusBar, + * NotificationPanelViewController, and LightRevealSrim so that we can run the unlocked screen + * off animation. + */ + private var initialized = false + private lateinit var lightRevealScrim: LightRevealScrim private var animatorDurationScale = 1f private var shouldAnimateInKeyguard = false private var lightRevealAnimationPlaying = false private var aodUiAnimationPlaying = false - private var callbacks = HashSet<Callback>() /** * The result of our decision whether to play the screen off animation in @@ -81,9 +88,6 @@ class UnlockedScreenOffAnimationController @Inject constructor( interpolator = Interpolators.LINEAR addUpdateListener { lightRevealScrim.revealAmount = it.animatedValue as Float - sendUnlockedScreenOffProgressUpdate( - 1f - (it.animatedFraction as Float), - 1f - (it.animatedValue as Float)) if (lightRevealScrim.isScrimAlmostOccludes && interactionJankMonitor.isInstrumenting(CUJ_SCREEN_OFF)) { // ends the instrument when the scrim almost occludes the screen. @@ -95,7 +99,6 @@ class UnlockedScreenOffAnimationController @Inject constructor( override fun onAnimationCancel(animation: Animator?) { lightRevealScrim.revealAmount = 1f lightRevealAnimationPlaying = false - sendUnlockedScreenOffProgressUpdate(0f, 0f) interactionJankMonitor.cancel(CUJ_SCREEN_OFF) } @@ -105,7 +108,8 @@ class UnlockedScreenOffAnimationController @Inject constructor( } override fun onAnimationStart(animation: Animator?) { - interactionJankMonitor.begin(statusBar.notificationShadeWindowView, CUJ_SCREEN_OFF) + interactionJankMonitor.begin( + mCentralSurfaces.notificationShadeWindowView, CUJ_SCREEN_OFF) } }) } @@ -117,11 +121,12 @@ class UnlockedScreenOffAnimationController @Inject constructor( } override fun initialize( - statusBar: StatusBar, + centralSurfaces: CentralSurfaces, lightRevealScrim: LightRevealScrim ) { + this.initialized = true this.lightRevealScrim = lightRevealScrim - this.statusBar = statusBar + this.mCentralSurfaces = centralSurfaces updateAnimatorDurationScale() globalSettings.registerContentObserver( @@ -176,9 +181,9 @@ class UnlockedScreenOffAnimationController @Inject constructor( // Lock the keyguard if it was waiting for the screen off animation to end. keyguardViewMediatorLazy.get().maybeHandlePendingLock() - // Tell the StatusBar to become keyguard for real - we waited on that since - // it is slow and would have caused the animation to jank. - statusBar.updateIsKeyguard() + // Tell the CentralSurfaces to become keyguard for real - we waited on that + // since it is slow and would have caused the animation to jank. + mCentralSurfaces.updateIsKeyguard() // Run the callback given to us by the KeyguardVisibilityHelper. after.run() @@ -196,7 +201,8 @@ class UnlockedScreenOffAnimationController @Inject constructor( override fun onAnimationStart(animation: Animator?) { interactionJankMonitor.begin( - statusBar.notificationShadeWindowView, CUJ_SCREEN_OFF_SHOW_AOD) + mCentralSurfaces.notificationShadeWindowView, + CUJ_SCREEN_OFF_SHOW_AOD) } }) .start() @@ -213,12 +219,12 @@ class UnlockedScreenOffAnimationController @Inject constructor( override fun onFinishedWakingUp() { // Set this to false in onFinishedWakingUp rather than onStartedWakingUp so that other - // observers (such as StatusBar) can ask us whether we were playing the screen off animation - // and reset accordingly. + // observers (such as CentralSurfaces) can ask us whether we were playing the screen off + // animation and reset accordingly. aodUiAnimationPlaying = false - // If we can't control the screen off animation, we shouldn't mess with the StatusBar's - // keyguard state unnecessarily. + // If we can't control the screen off animation, we shouldn't mess with the + // CentralSurfaces's keyguard state unnecessarily. if (dozeParameters.get().canControlUnlockedScreenOff()) { // Make sure the status bar is in the correct keyguard state, forcing it if necessary. // This is required if the screen off animation is cancelled, since it might be @@ -227,7 +233,7 @@ class UnlockedScreenOffAnimationController @Inject constructor( // even if we're going from SHADE to SHADE or KEYGUARD to KEYGUARD, since we might have // changed parts of the UI (such as showing AOD in the shade) without actually changing // the StatusBarState. This ensures that the UI definitely reflects the desired state. - statusBar.updateIsKeyguard(true /* forceStateChange */) + mCentralSurfaces.updateIsKeyguard(true /* forceStateChange */) } } @@ -249,7 +255,7 @@ class UnlockedScreenOffAnimationController @Inject constructor( // Show AOD. That'll cause the KeyguardVisibilityHelper to call // #animateInKeyguard. - statusBar.notificationPanelViewController.showAodUi() + mCentralSurfaces.notificationPanelViewController.showAodUi() } }, (ANIMATE_IN_KEYGUARD_DELAY * animatorDurationScale).toLong()) @@ -265,6 +271,18 @@ class UnlockedScreenOffAnimationController @Inject constructor( * on the current state of the device. */ fun shouldPlayUnlockedScreenOffAnimation(): Boolean { + // If we haven't been initialized yet, we don't have a StatusBar/LightRevealScrim yet, so we + // can't perform the animation. + if (!initialized) { + return false + } + + // If the device isn't in a state where we can control unlocked screen off (no AOD enabled, + // power save, etc.) then we shouldn't try to do so. + if (!dozeParameters.get().canControlUnlockedScreenOff()) { + return false + } + // If we explicitly already decided not to play the screen off animation, then never change // our mind. if (decidedToAnimateGoingToSleep == false) { @@ -285,8 +303,8 @@ class UnlockedScreenOffAnimationController @Inject constructor( // We currently draw both the light reveal scrim, and the AOD UI, in the shade. If it's // already expanded and showing notifications/QS, the animation looks really messy. For now, // disable it if the notification panel is not fully collapsed. - if ((!this::statusBar.isInitialized || - !statusBar.notificationPanelViewController.isFullyCollapsed) && + if ((!this::mCentralSurfaces.isInitialized || + !mCentralSurfaces.notificationPanelViewController.isFullyCollapsed) && // Status bar might be expanded because we have started // playing the animation already !isAnimationPlaying() @@ -307,21 +325,7 @@ class UnlockedScreenOffAnimationController @Inject constructor( } override fun shouldDelayDisplayDozeTransition(): Boolean = - dozeParameters.get().shouldControlUnlockedScreenOff() - - fun addCallback(callback: Callback) { - callbacks.add(callback) - } - - fun removeCallback(callback: Callback) { - callbacks.remove(callback) - } - - private fun sendUnlockedScreenOffProgressUpdate(linear: Float, eased: Float) { - callbacks.forEach { - it.onUnlockedScreenOffProgressUpdate(linear, eased) - } - } + shouldPlayUnlockedScreenOffAnimation() /** * Whether we're doing the light reveal animation or we're done with that and animating in the @@ -356,8 +360,4 @@ class UnlockedScreenOffAnimationController @Inject constructor( fun isScreenOffLightRevealAnimationPlaying(): Boolean { return lightRevealAnimationPlaying } - - interface Callback { - fun onUnlockedScreenOffProgressUpdate(linear: Float, eased: Float) - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java index ad8e79e36661..59c9d0baea3f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java @@ -22,16 +22,23 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; import com.android.keyguard.LockIconViewController; import com.android.systemui.biometrics.AuthRippleController; +import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.core.StatusBarInitializer; +import com.android.systemui.statusbar.notification.NotificationActivityStarter; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.collection.render.StatusBarNotifPanelEventSourceModule; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutListContainerModule; +import com.android.systemui.statusbar.phone.CentralSurfacesCommandQueueCallbacks; import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.NotificationShadeWindowView; import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController; import com.android.systemui.statusbar.phone.SplitShadeHeaderController; -import com.android.systemui.statusbar.phone.StatusBarCommandQueueCallbacks; import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener; +import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarterModule; +import com.android.systemui.statusbar.phone.StatusBarNotificationPresenterModule; import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment; import java.lang.annotation.Documented; @@ -45,7 +52,7 @@ import dagger.Subcomponent; /** * Dagger subcomponent for classes (semi-)related to the status bar. The component is created once - * inside {@link com.android.systemui.statusbar.phone.StatusBar} and never re-created. + * inside {@link com.android.systemui.statusbar.phone.CentralSurfaces} and never re-created. * * TODO(b/197137564): This should likely be re-factored a bit. It includes classes that aren't * directly related to status bar functionality, like multiple notification classes. And, the fact @@ -53,81 +60,82 @@ import dagger.Subcomponent; * outside the component. Should more items be moved *into* this component to avoid so many getters? */ @Subcomponent(modules = { + NotificationStackScrollLayoutListContainerModule.class, StatusBarNotifPanelEventSourceModule.class, - StatusBarViewModule.class + StatusBarViewModule.class, + StatusBarNotificationActivityStarterModule.class, + StatusBarNotificationPresenterModule.class, }) -@StatusBarComponent.StatusBarScope -public interface StatusBarComponent { +@CentralSurfacesComponent.CentralSurfacesScope +public interface CentralSurfacesComponent { /** - * Builder for {@link StatusBarComponent}. + * Builder for {@link CentralSurfacesComponent}. */ @Subcomponent.Factory interface Factory { - StatusBarComponent create(); + CentralSurfacesComponent create(); } /** - * Scope annotation for singleton items within the StatusBarComponent. + * Scope annotation for singleton items within the CentralSurfacesComponent. */ @Documented @Retention(RUNTIME) @Scope - @interface StatusBarScope {} + @interface CentralSurfacesScope {} + + /** + * Performs initialization logic after {@link CentralSurfacesComponent} has been constructed. + */ + interface Startable { + void start(); + void stop(); + } /** * Creates a {@link NotificationShadeWindowView}. */ - @StatusBarScope NotificationShadeWindowView getNotificationShadeWindowView(); /** */ - @StatusBarScope NotificationShelfController getNotificationShelfController(); /** */ - @StatusBarScope NotificationStackScrollLayoutController getNotificationStackScrollLayoutController(); /** * Creates a NotificationShadeWindowViewController. */ - @StatusBarScope NotificationShadeWindowViewController getNotificationShadeWindowViewController(); /** * Creates a NotificationPanelViewController. */ - @StatusBarScope NotificationPanelViewController getNotificationPanelViewController(); /** * Creates a LockIconViewController. Must be init after creation. */ - @StatusBarScope LockIconViewController getLockIconViewController(); /** * Creates an AuthRippleViewController. Must be init after creation. */ - @StatusBarScope AuthRippleController getAuthRippleController(); /** * Creates a StatusBarHeadsUpChangeListener. */ - @StatusBarScope StatusBarHeadsUpChangeListener getStatusBarHeadsUpChangeListener(); /** - * Creates a StatusBarCommandQueueCallbacks. + * Creates a CentralSurfacesCommandQueueCallbacks. */ - @StatusBarScope - StatusBarCommandQueueCallbacks getStatusBarCommandQueueCallbacks(); + CentralSurfacesCommandQueueCallbacks getCentralSurfacesCommandQueueCallbacks(); /** * Creates a SplitShadeHeaderController. */ - @StatusBarScope SplitShadeHeaderController getSplitShadeHeaderController(); /** @@ -140,20 +148,18 @@ public interface StatusBarComponent { /** * Creates a StatusBarInitializer */ - @StatusBarScope StatusBarInitializer getStatusBarInitializer(); /** - * Set of startables to be run after a StatusBarComponent has been constructed. + * Set of startables to be run after a CentralSurfacesComponent has been constructed. */ - @StatusBarScope Set<Startable> getStartables(); - /** - * Performs initialization logic after {@link StatusBarComponent} has been constructed. - */ - interface Startable { - void start(); - void stop(); - } + NotificationActivityStarter getNotificationActivityStarter(); + + NotificationPresenter getNotificationPresenter(); + + NotificationRowBinderImpl.BindRowCallback getBindRowCallback(); + + NotificationListContainer getNotificationListContainer(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index e6c239ff9a04..c024c7245c45 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -92,10 +92,9 @@ import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; -import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy; import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager; import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; @@ -127,16 +126,16 @@ import dagger.Module; import dagger.Provides; /** - * Dagger Module providing {@link StatusBar}. + * Dagger Module providing {@link CentralSurfaces}. */ @Module public interface StatusBarPhoneModule { /** - * Provides our instance of StatusBar which is considered optional. + * Provides our instance of CentralSurfaces which is considered optional. */ @Provides @SysUISingleton - static StatusBar provideStatusBar( + static CentralSurfaces provideCentralSurfaces( Context context, NotificationsController notificationsController, FragmentService fragmentService, @@ -196,10 +195,8 @@ public interface StatusBarPhoneModule { DozeScrimController dozeScrimController, VolumeComponent volumeComponent, CommandQueue commandQueue, - StatusBarComponent.Factory statusBarComponentFactory, + CentralSurfacesComponent.Factory statusBarComponentFactory, PluginManager pluginManager, - StatusBarNotificationActivityStarter.Builder - statusBarNotificationActivityStarterBuilder, ShadeController shadeController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, ViewMediatorCallback viewMediatorCallback, @@ -234,7 +231,7 @@ public interface StatusBarPhoneModule { DeviceStateManager deviceStateManager, DreamOverlayStateController dreamOverlayStateController, WiredChargingRippleController wiredChargingRippleController) { - return new StatusBar( + return new CentralSurfaces( context, notificationsController, fragmentService, @@ -296,7 +293,6 @@ public interface StatusBarPhoneModule { commandQueue, statusBarComponentFactory, pluginManager, - statusBarNotificationActivityStarterBuilder, shadeController, statusBarKeyguardViewManager, viewMediatorCallback, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java index ebd58fb8ebed..79fe700191f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java @@ -61,6 +61,9 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.tuner.TunerService; +import com.android.systemui.util.settings.SecureSettings; + +import java.util.concurrent.Executor; import javax.inject.Named; @@ -77,7 +80,7 @@ public abstract class StatusBarViewModule { /** */ @Provides - @StatusBarComponent.StatusBarScope + @CentralSurfacesComponent.CentralSurfacesScope public static NotificationShadeWindowView providesNotificationShadeWindowView( LayoutInflater layoutInflater) { NotificationShadeWindowView notificationShadeWindowView = (NotificationShadeWindowView) @@ -92,7 +95,7 @@ public abstract class StatusBarViewModule { /** */ @Provides - @StatusBarComponent.StatusBarScope + @CentralSurfacesComponent.CentralSurfacesScope public static NotificationStackScrollLayout providesNotificationStackScrollLayout( NotificationShadeWindowView notificationShadeWindowView) { return notificationShadeWindowView.findViewById(R.id.notification_stack_scroller); @@ -100,7 +103,7 @@ public abstract class StatusBarViewModule { /** */ @Provides - @StatusBarComponent.StatusBarScope + @CentralSurfacesComponent.CentralSurfacesScope public static NotificationShelf providesNotificationShelf(LayoutInflater layoutInflater, NotificationStackScrollLayout notificationStackScrollLayout) { NotificationShelf view = (NotificationShelf) layoutInflater.inflate( @@ -115,7 +118,7 @@ public abstract class StatusBarViewModule { /** */ @Provides - @StatusBarComponent.StatusBarScope + @CentralSurfacesComponent.CentralSurfacesScope public static NotificationShelfController providesStatusBarWindowView( NotificationShelfComponent.Builder notificationShelfComponentBuilder, NotificationShelf notificationShelf) { @@ -131,7 +134,7 @@ public abstract class StatusBarViewModule { /** */ @Provides - @StatusBarComponent.StatusBarScope + @CentralSurfacesComponent.CentralSurfacesScope public static NotificationPanelView getNotificationPanelView( NotificationShadeWindowView notificationShadeWindowView) { return notificationShadeWindowView.getNotificationPanelView(); @@ -139,7 +142,7 @@ public abstract class StatusBarViewModule { /** */ @Provides - @StatusBarComponent.StatusBarScope + @CentralSurfacesComponent.CentralSurfacesScope public static LockIconView getLockIconView( NotificationShadeWindowView notificationShadeWindowView) { return notificationShadeWindowView.findViewById(R.id.lock_icon_view); @@ -147,7 +150,7 @@ public abstract class StatusBarViewModule { /** */ @Provides - @StatusBarComponent.StatusBarScope + @CentralSurfacesComponent.CentralSurfacesScope @Nullable public static AuthRippleView getAuthRippleView( NotificationShadeWindowView notificationShadeWindowView) { @@ -157,7 +160,7 @@ public abstract class StatusBarViewModule { /** */ @Provides @Named(SPLIT_SHADE_HEADER) - @StatusBarComponent.StatusBarScope + @CentralSurfacesComponent.CentralSurfacesScope public static View getSplitShadeStatusBarView( NotificationShadeWindowView notificationShadeWindowView, FeatureFlags featureFlags) { @@ -172,7 +175,7 @@ public abstract class StatusBarViewModule { /** */ @Provides - @StatusBarComponent.StatusBarScope + @CentralSurfacesComponent.CentralSurfacesScope public static OngoingPrivacyChip getSplitShadeOngoingPrivacyChip( @Named(SPLIT_SHADE_HEADER) View header) { return header.findViewById(R.id.privacy_chip); @@ -180,21 +183,21 @@ public abstract class StatusBarViewModule { /** */ @Provides - @StatusBarComponent.StatusBarScope + @CentralSurfacesComponent.CentralSurfacesScope static StatusIconContainer providesStatusIconContainer(@Named(SPLIT_SHADE_HEADER) View header) { return header.findViewById(R.id.statusIcons); } /** */ @Provides - @StatusBarComponent.StatusBarScope + @CentralSurfacesComponent.CentralSurfacesScope @Named(SPLIT_SHADE_BATTERY_VIEW) static BatteryMeterView getBatteryMeterView(@Named(SPLIT_SHADE_HEADER) View view) { return view.findViewById(R.id.batteryRemainingIcon); } @Provides - @StatusBarComponent.StatusBarScope + @CentralSurfacesComponent.CentralSurfacesScope @Named(SPLIT_SHADE_BATTERY_CONTROLLER) static BatteryMeterViewController getBatteryMeterViewController( @Named(SPLIT_SHADE_BATTERY_VIEW) BatteryMeterView batteryMeterView, @@ -218,14 +221,14 @@ public abstract class StatusBarViewModule { /** */ @Provides - @StatusBarComponent.StatusBarScope + @CentralSurfacesComponent.CentralSurfacesScope public static TapAgainView getTapAgainView(NotificationPanelView npv) { return npv.getTapAgainView(); } /** */ @Provides - @StatusBarComponent.StatusBarScope + @CentralSurfacesComponent.CentralSurfacesScope public static NotificationsQuickSettingsContainer getNotificationsQuickSettingsContainer( NotificationShadeWindowView notificationShadeWindowView) { return notificationShadeWindowView.findViewById(R.id.notification_container_parent); @@ -235,9 +238,9 @@ public abstract class StatusBarViewModule { * Creates a new {@link CollapsedStatusBarFragment}. * * **IMPORTANT**: This method intentionally does not have - * {@link StatusBarComponent.StatusBarScope}, which means a new fragment *will* be created each - * time this method is called. This is intentional because we need fragments to re-created in - * certain lifecycle scenarios. + * {@link CentralSurfacesComponent.CentralSurfacesScope}, which means a new fragment *will* be + * created each time this method is called. This is intentional because we need fragments to + * re-created in certain lifecycle scenarios. * * This provider is {@link Named} such that it does not conflict with the provider inside of * {@link StatusBarFragmentComponent}. @@ -260,7 +263,9 @@ public abstract class StatusBarViewModule { StatusBarStateController statusBarStateController, CommandQueue commandQueue, CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger, - OperatorNameViewController.Factory operatorNameViewControllerFactory + OperatorNameViewController.Factory operatorNameViewControllerFactory, + SecureSettings secureSettings, + @Main Executor mainExecutor ) { return new CollapsedStatusBarFragment(statusBarFragmentComponentFactory, ongoingCallController, @@ -277,6 +282,8 @@ public abstract class StatusBarViewModule { statusBarStateController, commandQueue, collapsedStatusBarFragmentLogger, - operatorNameViewControllerFactory); + operatorNameViewControllerFactory, + secureSettings, + mainExecutor); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java index 2af077255869..2c84219dbfd0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java @@ -30,8 +30,10 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.app.Fragment; +import android.database.ContentObserver; import android.os.Bundle; import android.os.Parcelable; +import android.provider.Settings; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; @@ -39,8 +41,11 @@ import android.view.ViewGroup; import android.view.ViewStub; import android.widget.LinearLayout; +import androidx.annotation.VisibleForTesting; + import com.android.systemui.R; import com.android.systemui.animation.Interpolators; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; @@ -66,9 +71,11 @@ import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.EncryptionHelper; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.settings.SecureSettings; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; /** * Contains the collapsed status bar and handles hiding/showing based on disable flags @@ -110,6 +117,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue private final PanelExpansionStateManager mPanelExpansionStateManager; private final StatusBarIconController mStatusBarIconController; private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; + private final SecureSettings mSecureSettings; + private final Executor mMainExecutor; private List<String> mBlockedIcons = new ArrayList<>(); @@ -145,7 +154,9 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue StatusBarStateController statusBarStateController, CommandQueue commandQueue, CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger, - OperatorNameViewController.Factory operatorNameViewControllerFactory + OperatorNameViewController.Factory operatorNameViewControllerFactory, + SecureSettings secureSettings, + @Main Executor mainExecutor ) { mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory; mOngoingCallController = ongoingCallController; @@ -163,6 +174,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mCommandQueue = commandQueue; mCollapsedStatusBarFragmentLogger = collapsedStatusBarFragmentLogger; mOperatorNameViewControllerFactory = operatorNameViewControllerFactory; + mSecureSettings = secureSettings; + mMainExecutor = mainExecutor; } @Override @@ -187,10 +200,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue } mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons), mFeatureFlags); mDarkIconManager.setShouldLog(true); - mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_volume)); - mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_alarm_clock)); - mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_call_strength)); - mDarkIconManager.setBlockList(mBlockedIcons); + updateBlockedIcons(); mStatusBarIconController.addIconGroup(mDarkIconManager); mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area); mClockView = mStatusBar.findViewById(R.id.clock); @@ -203,6 +213,24 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mAnimationScheduler.addCallback(this); } + @VisibleForTesting + void updateBlockedIcons() { + mBlockedIcons.clear(); + + if (mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0) == 0) { + mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_volume)); + } + mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_alarm_clock)); + mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_call_strength)); + + mMainExecutor.execute(() -> mDarkIconManager.setBlockList(mBlockedIcons)); + } + + @VisibleForTesting + List<String> getBlockedIcons() { + return mBlockedIcons; + } + @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -217,6 +245,11 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mCommandQueue.addCallback(this); mStatusBarStateController.addCallback(this); initOngoingCallChip(); + + mSecureSettings.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON), + false, + mVolumeSettingObserver); } @Override @@ -225,6 +258,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mCommandQueue.removeCallback(this); mStatusBarStateController.removeCallback(this); mOngoingCallController.removeCallback(mOngoingCallListener); + mSecureSettings.unregisterContentObserver(mVolumeSettingObserver); } @Override @@ -584,6 +618,13 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mLocationPublisher.updateStatusBarMargin(leftMargin, rightMargin); } + private final ContentObserver mVolumeSettingObserver = new ContentObserver(null) { + @Override + public void onChange(boolean selfChange) { + updateBlockedIcons(); + } + }; + // Listen for view end changes of PhoneStatusBarView and publish that to the privacy dot private View.OnLayoutChangeListener mStatusBarLayoutListener = (view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java index 22b7f649775e..2eba325ff63d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java @@ -18,12 +18,14 @@ package com.android.systemui.statusbar.phone.fragment.dagger; import com.android.systemui.battery.BatteryMeterViewController; import com.android.systemui.dagger.qualifiers.RootView; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; import com.android.systemui.statusbar.phone.LightsOutNotifController; import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions; import com.android.systemui.statusbar.phone.PhoneStatusBarView; import com.android.systemui.statusbar.phone.PhoneStatusBarViewController; import com.android.systemui.statusbar.phone.StatusBarDemoMode; +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment; import dagger.BindsInstance; @@ -39,12 +41,6 @@ import dagger.Subcomponent; * * Anything that depends on {@link CollapsedStatusBarFragment} or {@link PhoneStatusBarView} * should be included here or in {@link StatusBarFragmentModule}. - * - * Note that this is completely separate from - * {@link com.android.systemui.statusbar.phone.dagger.StatusBarComponent}. This component gets - * re-created on each new fragment creation, whereas - * {@link com.android.systemui.statusbar.phone.dagger.StatusBarComponent} is only created once in - * {@link com.android.systemui.statusbar.phone.StatusBar} and never re-created. */ @Subcomponent(modules = {StatusBarFragmentModule.class}) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt index 6e7231ef5ca3..982ccfd4dffa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt @@ -21,6 +21,7 @@ import android.app.IActivityManager import android.app.IUidObserver import android.app.Notification import android.app.Notification.CallStyle.CALL_TYPE_ONGOING +import android.content.Context import android.content.Intent import android.util.Log import android.view.View @@ -52,6 +53,7 @@ import javax.inject.Inject */ @SysUISingleton class OngoingCallController @Inject constructor( + private val context: Context, private val notifCollection: CommonNotifCollection, private val ongoingCallFlags: OngoingCallFlags, private val systemClock: SystemClock, @@ -67,13 +69,10 @@ class OngoingCallController @Inject constructor( private var isFullscreen: Boolean = false /** Non-null if there's an active call notification. */ private var callNotificationInfo: CallNotificationInfo? = null - /** True if the application managing the call is visible to the user. */ - private var isCallAppVisible: Boolean = false private var chipView: View? = null - private var uidObserver: IUidObserver.Stub? = null private val mListeners: MutableList<OngoingCallListener> = mutableListOf() - + private val uidObserver = CallAppUidObserver() private val notifListener = object : NotifCollectionListener { // Temporary workaround for b/178406514 for testing purposes. // @@ -158,7 +157,7 @@ class OngoingCallController @Inject constructor( fun hasOngoingCall(): Boolean { return callNotificationInfo?.isOngoing == true && // When the user is in the phone app, don't show the chip. - !isCallAppVisible + !uidObserver.isCallAppVisible } override fun addCallback(listener: OngoingCallListener) { @@ -194,7 +193,7 @@ class OngoingCallController @Inject constructor( } updateChipClickListener() - setUpUidObserver(currentCallNotificationInfo) + uidObserver.registerWithUid(currentCallNotificationInfo.uid) if (!currentCallNotificationInfo.statusBarSwipedAway) { statusBarWindowController.ifPresent { it.setOngoingProcessRequiresStatusBarVisible(true) @@ -238,62 +237,6 @@ class OngoingCallController @Inject constructor( } } - /** - * Sets up an [IUidObserver] to monitor the status of the application managing the ongoing call. - */ - private fun setUpUidObserver(currentCallNotificationInfo: CallNotificationInfo) { - try { - isCallAppVisible = isProcessVisibleToUser( - iActivityManager.getUidProcessState(currentCallNotificationInfo.uid, null) - ) - } catch (se: SecurityException) { - Log.e(TAG, "Security exception when trying to get process state: $se") - return - } - - if (uidObserver != null) { - iActivityManager.unregisterUidObserver(uidObserver) - } - - uidObserver = object : IUidObserver.Stub() { - override fun onUidStateChanged( - uid: Int, - procState: Int, - procStateSeq: Long, - capability: Int - ) { - if (uid == currentCallNotificationInfo.uid) { - val oldIsCallAppVisible = isCallAppVisible - isCallAppVisible = isProcessVisibleToUser(procState) - if (oldIsCallAppVisible != isCallAppVisible) { - // Animations may be run as a result of the call's state change, so ensure - // the listener is notified on the main thread. - mainExecutor.execute { - mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) } - } - } - } - } - - override fun onUidGone(uid: Int, disabled: Boolean) {} - override fun onUidActive(uid: Int) {} - override fun onUidIdle(uid: Int, disabled: Boolean) {} - override fun onUidCachedChanged(uid: Int, cached: Boolean) {} - } - - try { - iActivityManager.registerUidObserver( - uidObserver, - ActivityManager.UID_OBSERVER_PROCSTATE, - ActivityManager.PROCESS_STATE_UNKNOWN, - null - ) - } catch (se: SecurityException) { - Log.e(TAG, "Security exception when trying to register uid observer: $se") - return - } - } - /** Returns true if the given [procState] represents a process that's visible to the user. */ private fun isProcessVisibleToUser(procState: Int): Boolean { return procState <= ActivityManager.PROCESS_STATE_TOP @@ -306,7 +249,7 @@ class OngoingCallController @Inject constructor( swipeStatusBarAwayGestureHandler.ifPresent { it.removeOnGestureDetectedCallback(TAG) } } else { swipeStatusBarAwayGestureHandler.ifPresent { - it.addOnGestureDetectedCallback(TAG, this::onSwipeAwayGestureDetected) + it.addOnGestureDetectedCallback(TAG) { _ -> onSwipeAwayGestureDetected() } } } } @@ -317,9 +260,7 @@ class OngoingCallController @Inject constructor( statusBarWindowController.ifPresent { it.setOngoingProcessRequiresStatusBarVisible(false) } swipeStatusBarAwayGestureHandler.ifPresent { it.removeOnGestureDetectedCallback(TAG) } mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) } - if (uidObserver != null) { - iActivityManager.unregisterUidObserver(uidObserver) - } + uidObserver.unregister() } /** Tear down anything related to the chip view to prevent leaks. */ @@ -376,7 +317,84 @@ class OngoingCallController @Inject constructor( override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { pw.println("Active call notification: $callNotificationInfo") - pw.println("Call app visible: $isCallAppVisible") + pw.println("Call app visible: ${uidObserver.isCallAppVisible}") + } + + /** Our implementation of a [IUidObserver]. */ + inner class CallAppUidObserver : IUidObserver.Stub() { + /** True if the application managing the call is visible to the user. */ + var isCallAppVisible: Boolean = false + private set + + /** The UID of the application managing the call. Null if there is no active call. */ + private var callAppUid: Int? = null + + /** + * True if this observer is currently registered with the activity manager and false + * otherwise. + */ + private var isRegistered = false + + + /** Register this observer with the activity manager and the given [uid]. */ + fun registerWithUid(uid: Int) { + if (callAppUid == uid) { + return + } + callAppUid = uid + + try { + isCallAppVisible = isProcessVisibleToUser( + iActivityManager.getUidProcessState(uid, context.opPackageName) + ) + if (isRegistered) { + return + } + iActivityManager.registerUidObserver( + uidObserver, + ActivityManager.UID_OBSERVER_PROCSTATE, + ActivityManager.PROCESS_STATE_UNKNOWN, + context.opPackageName + ) + isRegistered = true + } catch (se: SecurityException) { + Log.e(TAG, "Security exception when trying to set up uid observer: $se") + } + } + + /** Unregister this observer with the activity manager. */ + fun unregister() { + callAppUid = null + isRegistered = false + iActivityManager.unregisterUidObserver(uidObserver) + } + + override fun onUidStateChanged( + uid: Int, + procState: Int, + procStateSeq: Long, + capability: Int + ) { + val currentCallAppUid = callAppUid ?: return + if (uid != currentCallAppUid) { + return + } + + val oldIsCallAppVisible = isCallAppVisible + isCallAppVisible = isProcessVisibleToUser(procState) + if (oldIsCallAppVisible != isCallAppVisible) { + // Animations may be run as a result of the call's state change, so ensure + // the listener is notified on the main thread. + mainExecutor.execute { + mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) } + } + } + } + + override fun onUidGone(uid: Int, disabled: Boolean) {} + override fun onUidActive(uid: Int) {} + override fun onUidIdle(uid: Int, disabled: Boolean) {} + override fun onUidCachedChanged(uid: Int, cached: Boolean) {} } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt index 3a1491400f38..60f6df66cb5a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt @@ -25,7 +25,7 @@ import android.util.Log import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.DisplayId import com.android.systemui.statusbar.CommandQueue -import com.android.systemui.statusbar.phone.StatusBar +import com.android.systemui.statusbar.phone.CentralSurfaces import javax.inject.Inject /** @@ -80,8 +80,8 @@ class StatusBarWindowStateController @Inject constructor( } windowState = state - if (StatusBar.DEBUG_WINDOW_STATE) { - Log.d(StatusBar.TAG, "Status bar " + windowStateToString(state)) + if (CentralSurfaces.DEBUG_WINDOW_STATE) { + Log.d(CentralSurfaces.TAG, "Status bar " + windowStateToString(state)) } listeners.forEach { it.onStatusBarWindowStateChanged(state) } } diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt index e2374ada15d5..d6dfceac7a63 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt @@ -26,7 +26,7 @@ import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.phone.ScreenOffAnimation -import com.android.systemui.statusbar.phone.StatusBar +import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.policy.CallbackController import com.android.systemui.unfold.FoldAodAnimationController.FoldAodAnimationStatus import com.android.systemui.util.settings.GlobalSettings @@ -50,7 +50,7 @@ constructor( private val globalSettings: GlobalSettings ) : CallbackController<FoldAodAnimationStatus>, ScreenOffAnimation, WakefulnessLifecycle.Observer { - private lateinit var statusBar: StatusBar + private lateinit var mCentralSurfaces: CentralSurfaces private var isFolded = false private var isFoldHandled = true @@ -66,14 +66,14 @@ constructor( private val statusListeners = arrayListOf<FoldAodAnimationStatus>() private val startAnimationRunnable = Runnable { - statusBar.notificationPanelViewController.startFoldToAodAnimation { + mCentralSurfaces.notificationPanelViewController.startFoldToAodAnimation { // End action setAnimationState(playing = false) } } - override fun initialize(statusBar: StatusBar, lightRevealScrim: LightRevealScrim) { - this.statusBar = statusBar + override fun initialize(centralSurfaces: CentralSurfaces, lightRevealScrim: LightRevealScrim) { + this.mCentralSurfaces = centralSurfaces deviceStateManager.registerCallback(executor, FoldListener()) wakefulnessLifecycle.addObserver(this) @@ -88,7 +88,7 @@ constructor( globalSettings.getString(Settings.Global.ANIMATOR_DURATION_SCALE) != "0" ) { setAnimationState(playing = true) - statusBar.notificationPanelViewController.prepareFoldToAodAnimation() + mCentralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation() true } else { setAnimationState(playing = false) @@ -98,7 +98,7 @@ constructor( override fun onStartedWakingUp() { if (isAnimationPlaying) { handler.removeCallbacks(startAnimationRunnable) - statusBar.notificationPanelViewController.cancelFoldToAodAnimation() + mCentralSurfaces.notificationPanelViewController.cancelFoldToAodAnimation() } setAnimationState(playing = false) @@ -131,12 +131,14 @@ constructor( // We should play the folding to AOD animation setAnimationState(playing = true) - statusBar.notificationPanelViewController.prepareFoldToAodAnimation() + mCentralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation() // We don't need to wait for the scrim as it is already displayed // but we should wait for the initial animation preparations to be drawn // (setting initial alpha/translation) - OneShotPreDrawListener.add(statusBar.notificationPanelViewController.view, onReady) + OneShotPreDrawListener.add( + mCentralSurfaces.notificationPanelViewController.view, onReady + ) } else { // No animation, call ready callback immediately onReady.run() diff --git a/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt b/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt new file mode 100644 index 000000000000..613a797f020c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt @@ -0,0 +1,26 @@ +package com.android.systemui.util.view + +import android.view.View +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject + +/** + * A class with generic view utility methods. + * + * Doesn't use static methods so that it can be easily mocked out in tests. + */ +@SysUISingleton +class ViewUtil @Inject constructor() { + /** + * Returns true if the given (x, y) point (in screen coordinates) is within the status bar + * view's range and false otherwise. + */ + fun touchIsWithinView(view: View, x: Float, y: Float): Boolean { + val left = view.locationOnScreen[0] + val top = view.locationOnScreen[1] + return left <= x && + x <= left + view.width && + top <= y && + y <= top + view.height + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt index 5128ccc15d9d..ec2c1de49b4c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt @@ -32,7 +32,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.KeyguardBypassController -import com.android.systemui.statusbar.phone.StatusBar +import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.leak.RotationUtils @@ -61,7 +61,7 @@ class AuthRippleControllerTest : SysuiTestCase() { private lateinit var staticMockSession: MockitoSession private lateinit var controller: AuthRippleController - @Mock private lateinit var statusBar: StatusBar + @Mock private lateinit var mCentralSurfaces: CentralSurfaces @Mock private lateinit var rippleView: AuthRippleView @Mock private lateinit var commandRegistry: CommandRegistry @Mock private lateinit var configurationController: ConfigurationController @@ -89,7 +89,7 @@ class AuthRippleControllerTest : SysuiTestCase() { `when`(udfpsControllerProvider.get()).thenReturn(udfpsController) controller = AuthRippleController( - statusBar, + mCentralSurfaces, context, authController, configurationController, @@ -105,7 +105,7 @@ class AuthRippleControllerTest : SysuiTestCase() { rippleView ) controller.init() - `when`(statusBar.lightRevealScrim).thenReturn(lightRevealScrim) + `when`(mCentralSurfaces.lightRevealScrim).thenReturn(lightRevealScrim) } @After diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index 35e838bfca9a..1856fda14e1b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -65,7 +65,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.SystemUIDialogManager; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; @@ -121,7 +121,7 @@ public class UdfpsControllerTest extends SysuiTestCase { @Mock private StatusBarStateController mStatusBarStateController; @Mock - private StatusBar mStatusBar; + private CentralSurfaces mCentralSurfaces; @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java index e9a4e15b9773..7fb42b6ea11e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java @@ -166,7 +166,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { mController.onViewAttached(); verify(mView, atLeast(1)).setPauseAuth(true); - verify(mView).onDozeAmountChanged(dozeAmount, dozeAmount); + verify(mView).onDozeAmountChanged(dozeAmount, dozeAmount, true); } @Test @@ -193,7 +193,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { final float eased = .65f; mStatusBarStateListener.onDozeAmountChanged(linear, eased); - verify(mView).onDozeAmountChanged(linear, eased); + verify(mView).onDozeAmountChanged(linear, eased, true); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt index 9908d44507cd..da25c6202b21 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt @@ -16,15 +16,22 @@ package com.android.systemui.controls.ui +import android.database.ContentObserver +import android.net.Uri +import android.os.Handler +import android.provider.Settings +import android.test.suitebuilder.annotation.SmallTest import android.testing.AndroidTestingRunner -import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.controls.ControlsMetricsLogger import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.mockito.any +import com.android.systemui.util.settings.SecureSettings import com.android.wm.shell.TaskViewFactory +import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -44,7 +51,6 @@ import java.util.Optional @SmallTest @RunWith(AndroidTestingRunner::class) class ControlActionCoordinatorImplTest : SysuiTestCase() { - @Mock private lateinit var vibratorHelper: VibratorHelper @Mock @@ -61,6 +67,10 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { private lateinit var cvh: ControlViewHolder @Mock private lateinit var metricsLogger: ControlsMetricsLogger + @Mock + private lateinit var secureSettings: SecureSettings + @Mock + private lateinit var mainHandler: Handler companion object { fun <T> any(): T = Mockito.any<T>() @@ -75,16 +85,24 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) + `when`(secureSettings.getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS)) + .thenReturn(Settings.Secure + .getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS)) + coordinator = spy(ControlActionCoordinatorImpl( - mContext, - bgExecutor, - uiExecutor, - activityStarter, - keyguardStateController, - taskViewFactory, - metricsLogger, - vibratorHelper - )) + mContext, + bgExecutor, + uiExecutor, + activityStarter, + keyguardStateController, + taskViewFactory, + metricsLogger, + vibratorHelper, + secureSettings, + mainHandler)) + + verify(secureSettings).registerContentObserver(any(Uri::class.java), + anyBoolean(), any(ContentObserver::class.java)) `when`(cvh.cws.ci.controlId).thenReturn(ID) `when`(cvh.cws.control?.isAuthRequired()).thenReturn(true) @@ -126,10 +144,23 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { fun testToggleRunsWhenLockedAndAuthNotRequired() { `when`(keyguardStateController.isShowing()).thenReturn(true) `when`(keyguardStateController.isUnlocked()).thenReturn(false) - `when`(cvh.cws.control?.isAuthRequired()).thenReturn(false) + doReturn(false).`when`(coordinator).isAuthRequired( + any(), anyBoolean()) coordinator.toggle(cvh, "", true) + verify(coordinator).bouncerOrRun(action, false /* authRequired */) verify(action).invoke() } + + @Test + fun testIsAuthRequired() { + `when`(cvh.cws.control?.isAuthRequired).thenReturn(true) + assertThat(coordinator.isAuthRequired(cvh, false)).isTrue() + + `when`(cvh.cws.control?.isAuthRequired).thenReturn(false) + assertThat(coordinator.isAuthRequired(cvh, false)).isTrue() + + assertThat(coordinator.isAuthRequired(cvh, true)).isFalse() + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java index 56844292ce4a..3340f2fd5749 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java @@ -143,8 +143,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testInitialize_dozeSuppressed_alwaysOnDisabled_goesToDoze() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testInitialize_alwaysOnSuppressed_alwaysOnDisabled_goesToDoze() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false); mMachine.requestState(INITIALIZED); @@ -154,8 +154,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testInitialize_dozeSuppressed_alwaysOnEnabled_goesToDoze() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testInitialize_alwaysOnSuppressed_alwaysOnEnabled_goesToDoze() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); mMachine.requestState(INITIALIZED); @@ -165,8 +165,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testInitialize_dozeSuppressed_afterDocked_goesToDoze() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testInitialize_alwaysOnSuppressed_afterDocked_goesToDoze() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true); mMachine.requestState(INITIALIZED); @@ -176,8 +176,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testInitialize_dozeSuppressed_alwaysOnDisabled_afterDockPaused_goesToDoze() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testInitialize_alwaysOnSuppressed_alwaysOnDisabled_afterDockPaused_goesToDoze() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false); when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isHidden()).thenReturn(true); @@ -189,8 +189,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testInitialize_dozeSuppressed_alwaysOnEnabled_afterDockPaused_goesToDoze() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testInitialize_alwaysOnSuppressed_alwaysOnEnabled_afterDockPaused_goesToDoze() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isHidden()).thenReturn(true); @@ -228,8 +228,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testPulseDone_dozeSuppressed_goesToSuppressed() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testPulseDone_alwaysOnSuppressed_goesToSuppressed() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); mMachine.requestState(INITIALIZED); mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); @@ -266,8 +266,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testPulseDone_dozeSuppressed_afterDocked_goesToDoze() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testPulseDone_alwaysOnSuppressed_afterDocked_goesToDoze() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true); mMachine.requestState(INITIALIZED); mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); @@ -295,8 +295,8 @@ public class DozeMachineTest extends SysuiTestCase { } @Test - public void testPulseDone_dozeSuppressed_afterDockPaused_goesToDoze() { - when(mHost.isDozeSuppressed()).thenReturn(true); + public void testPulseDone_alwaysOnSuppressed_afterDockPaused_goesToDoze() { + when(mHost.isAlwaysOnSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isHidden()).thenReturn(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java new file mode 100644 index 000000000000..aa0a909622bb --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java @@ -0,0 +1,231 @@ +/* + * 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 andatest + * limitations under the License. + */ + +package com.android.systemui.doze; + +import static com.android.systemui.doze.DozeMachine.State.DOZE; +import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD; +import static com.android.systemui.doze.DozeMachine.State.FINISH; +import static com.android.systemui.doze.DozeMachine.State.INITIALIZED; +import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED; + +import static org.mockito.Matchers.anyObject; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.UiModeManager; +import android.content.BroadcastReceiver; +import android.content.res.Configuration; +import android.hardware.display.AmbientDisplayConfiguration; +import android.testing.AndroidTestingRunner; +import android.testing.UiThreadTest; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.statusbar.phone.BiometricUnlockController; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import dagger.Lazy; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@UiThreadTest +public class DozeSuppressorTest extends SysuiTestCase { + + DozeSuppressor mDozeSuppressor; + @Mock + private DozeLog mDozeLog; + @Mock + private DozeHost mDozeHost; + @Mock + private AmbientDisplayConfiguration mConfig; + @Mock + private BroadcastDispatcher mBroadcastDispatcher; + @Mock + private UiModeManager mUiModeManager; + @Mock + private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; + @Mock + private BiometricUnlockController mBiometricUnlockController; + + @Mock + private DozeMachine mDozeMachine; + + @Captor + private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor; + private BroadcastReceiver mBroadcastReceiver; + + @Captor + private ArgumentCaptor<DozeHost.Callback> mDozeHostCaptor; + private DozeHost.Callback mDozeHostCallback; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + // setup state for NOT ending doze immediately + when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController); + when(mBiometricUnlockController.hasPendingAuthentication()).thenReturn(false); + when(mDozeHost.isProvisioned()).thenReturn(true); + + mDozeSuppressor = new DozeSuppressor( + mDozeHost, + mConfig, + mDozeLog, + mBroadcastDispatcher, + mUiModeManager, + mBiometricUnlockControllerLazy); + + mDozeSuppressor.setDozeMachine(mDozeMachine); + } + + @After + public void tearDown() { + mDozeSuppressor.destroy(); + } + + @Test + public void testRegistersListenersOnInitialized_unregisteredOnFinish() { + // check that receivers and callbacks registered + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + captureBroadcastReceiver(); + captureDozeHostCallback(); + + // check that receivers and callbacks are unregistered + mDozeSuppressor.transitionTo(INITIALIZED, FINISH); + verify(mBroadcastDispatcher).unregisterReceiver(mBroadcastReceiver); + verify(mDozeHost).removeCallback(mDozeHostCallback); + } + + @Test + public void testEndDoze_carMode() { + // GIVEN car mode + when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_CAR); + + // WHEN dozing begins + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + + // THEN doze immediately ends + verify(mDozeMachine).requestState(FINISH); + } + + @Test + public void testEndDoze_unprovisioned() { + // GIVEN device unprovisioned + when(mDozeHost.isProvisioned()).thenReturn(false); + + // WHEN dozing begins + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + + // THEN doze immediately ends + verify(mDozeMachine).requestState(FINISH); + } + + @Test + public void testEndDoze_hasPendingUnlock() { + // GIVEN device unprovisioned + when(mBiometricUnlockController.hasPendingAuthentication()).thenReturn(true); + + // WHEN dozing begins + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + + // THEN doze immediately ends + verify(mDozeMachine).requestState(FINISH); + } + + @Test + public void testPowerSaveChanged_active() { + // GIVEN AOD power save is active and doze is initialized + when(mDozeHost.isPowerSaveActive()).thenReturn(true); + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + captureDozeHostCallback(); + + // WHEN power save change gets triggered (even if active = false, since it + // may differ from the aodPowerSaveActive state reported by DostHost) + mDozeHostCallback.onPowerSaveChanged(false); + + // THEN the state changes to DOZE + verify(mDozeMachine).requestState(DOZE); + } + + @Test + public void testPowerSaveChanged_notActive() { + // GIVEN DOZE (not showing aod content) + when(mConfig.alwaysOnEnabled(anyInt())).thenReturn(true); + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + when(mDozeMachine.getState()).thenReturn(DOZE); + captureDozeHostCallback(); + + // WHEN power save mode is no longer active + when(mDozeHost.isPowerSaveActive()).thenReturn(false); + mDozeHostCallback.onPowerSaveChanged(false); + + // THEN the state changes to DOZE_AOD + verify(mDozeMachine).requestState(DOZE_AOD); + } + + @Test + public void testAlwaysOnSuppressedChanged_nowSuppressed() { + // GIVEN DOZE_AOD + when(mConfig.alwaysOnEnabled(anyInt())).thenReturn(true); + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + when(mDozeMachine.getState()).thenReturn(DOZE_AOD); + captureDozeHostCallback(); + + // WHEN alwaysOnSuppressedChanged to suppressed=true + mDozeHostCallback.onAlwaysOnSuppressedChanged(true); + + // THEN DOZE requested + verify(mDozeMachine).requestState(DOZE); + } + + @Test + public void testAlwaysOnSuppressedChanged_notSuppressed() { + // GIVEN DOZE + when(mConfig.alwaysOnEnabled(anyInt())).thenReturn(true); + mDozeSuppressor.transitionTo(UNINITIALIZED, INITIALIZED); + when(mDozeMachine.getState()).thenReturn(DOZE); + captureDozeHostCallback(); + + // WHEN alwaysOnSuppressedChanged to suppressed=false + mDozeHostCallback.onAlwaysOnSuppressedChanged(false); + + // THEN DOZE_AOD requested + verify(mDozeMachine).requestState(DOZE_AOD); + } + + private void captureDozeHostCallback() { + verify(mDozeHost).addCallback(mDozeHostCaptor.capture()); + mDozeHostCallback = mDozeHostCaptor.getValue(); + } + + private void captureBroadcastReceiver() { + verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiverCaptor.capture(), + anyObject()); + mBroadcastReceiver = mBroadcastReceiverCaptor.getValue(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java index 21768edd40e9..2860b50c2295 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java @@ -152,19 +152,19 @@ public class DreamOverlayServiceTest extends SysuiTestCase { } @Test - public void testShouldShowComplicationsTrueByDefault() { + public void testShouldShowComplicationsFalseByDefault() { mService.onBind(new Intent()); - assertThat(mService.shouldShowComplications()).isTrue(); + assertThat(mService.shouldShowComplications()).isFalse(); } @Test public void testShouldShowComplicationsSetByIntentExtra() { final Intent intent = new Intent(); - intent.putExtra(DreamService.EXTRA_SHOW_COMPLICATIONS, false); + intent.putExtra(DreamService.EXTRA_SHOW_COMPLICATIONS, true); mService.onBind(intent); - assertThat(mService.shouldShowComplications()).isFalse(); + assertThat(mService.shouldShowComplications()).isTrue(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java index 49da4bd5a825..3ce9889571f1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java @@ -158,6 +158,7 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase { public void testComplicationFilteringWhenShouldShowComplications() { final DreamOverlayStateController stateController = new DreamOverlayStateController(mExecutor); + stateController.setShouldShowComplications(true); final Complication alwaysAvailableComplication = Mockito.mock(Complication.class); final Complication weatherComplication = Mockito.mock(Complication.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java index ad8d44d62a5c..a32ff801e824 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java @@ -17,19 +17,34 @@ package com.android.systemui.dreams; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.AlarmManager; +import android.content.res.Resources; +import android.hardware.SensorPrivacyManager; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.provider.Settings; +import android.service.notification.NotificationListenerService; +import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; +import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.NotificationListener; +import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController; +import com.android.systemui.statusbar.policy.NextAlarmController; +import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.touch.TouchInsetManager; +import com.android.systemui.util.time.DateFormatUtil; import org.junit.Before; import org.junit.Test; @@ -41,6 +56,8 @@ import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { + private static final String NOTIFICATION_INDICATOR_FORMATTER_STRING = + "{count, plural, =1 {# notification} other {# notifications}}"; @Mock DreamOverlayStatusBarView mView; @@ -52,14 +69,55 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { Network mNetwork; @Mock TouchInsetManager.TouchInsetSession mTouchSession; + @Mock + Resources mResources; + @Mock + AlarmManager mAlarmManager; + @Mock + AlarmManager.AlarmClockInfo mAlarmClockInfo; + @Mock + NextAlarmController mNextAlarmController; + @Mock + DateFormatUtil mDateFormatUtil; + @Mock + IndividualSensorPrivacyController mSensorPrivacyController; + @Mock + StatusBarNotification mStatusBarNotification; + @Mock + NotificationListenerService.RankingMap mRankingMap; + @Mock + NotificationListener mNotificationListener; + @Mock + ZenModeController mZenModeController; DreamOverlayStatusBarViewController mController; @Before public void setup() { MockitoAnnotations.initMocks(this); - mController = new DreamOverlayStatusBarViewController(mView, mConnectivityManager, - mTouchSession); + + when(mResources.getString(R.string.dream_overlay_status_bar_notification_indicator)) + .thenReturn(NOTIFICATION_INDICATOR_FORMATTER_STRING); + + mController = new DreamOverlayStatusBarViewController( + mView, + mResources, + mConnectivityManager, + mTouchSession, + mAlarmManager, + mNextAlarmController, + mDateFormatUtil, + mSensorPrivacyController, + mNotificationListener, + mZenModeController); + } + + @Test + public void testOnViewAttachedAddsCallbacks() { + mController.onViewAttached(); + verify(mNextAlarmController).addCallback(any()); + verify(mSensorPrivacyController).addCallback(any()); + verify(mZenModeController).addCallback(any()); } @Test @@ -71,28 +129,97 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { } @Test - public void testOnViewAttachedShowsWifiStatusWhenWifiUnavailable() { + public void testOnViewAttachedShowsWifiIconWhenWifiUnavailable() { when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) .thenReturn(false); when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities); mController.onViewAttached(); - verify(mView).showWifiStatus(true); + verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true); } @Test - public void testOnViewAttachedHidesWifiStatusWhenWifiAvailable() { + public void testOnViewAttachedHidesWifiIconWhenWifiAvailable() { when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) .thenReturn(true); when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities); mController.onViewAttached(); - verify(mView).showWifiStatus(false); + verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false); } @Test - public void testOnViewAttachedShowsWifiStatusWhenNetworkCapabilitiesUnavailable() { + public void testOnViewAttachedShowsWifiIconWhenNetworkCapabilitiesUnavailable() { when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(null); mController.onViewAttached(); - verify(mView).showWifiStatus(true); + } + + @Test + public void testOnViewAttachedShowsAlarmIconWhenAlarmExists() { + when(mAlarmClockInfo.getTriggerTime()).thenReturn(1L); + when(mAlarmManager.getNextAlarmClock(anyInt())).thenReturn(mAlarmClockInfo); + mController.onViewAttached(); + verify(mView).showIcon( + eq(DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET), eq(true), any()); + } + + @Test + public void testOnViewAttachedHidesAlarmIconWhenNoAlarmExists() { + when(mAlarmManager.getNextAlarmClock(anyInt())).thenReturn(null); + mController.onViewAttached(); + verify(mView).showIcon( + eq(DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET), eq(false), isNull()); + } + + @Test + public void testOnViewAttachedShowsMicCameraIconWhenDisabled() { + when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE)) + .thenReturn(true); + when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA)) + .thenReturn(true); + mController.onViewAttached(); + verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true); + } + + @Test + public void testOnViewAttachedHidesMicCameraIconWhenEnabled() { + when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE)) + .thenReturn(false); + when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA)) + .thenReturn(false); + mController.onViewAttached(); + verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false); + } + + @Test + public void testOnViewAttachedShowsNotificationsIconWhenNotificationsExist() { + StatusBarNotification[] notifications = { mStatusBarNotification }; + when(mNotificationListener.getActiveNotifications()).thenReturn(notifications); + mController.onViewAttached(); + verify(mView).showIcon( + eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any()); + } + + @Test + public void testOnViewAttachedHidesNotificationsIconWhenNoNotificationsExist() { + when(mNotificationListener.getActiveNotifications()).thenReturn(null); + mController.onViewAttached(); + verify(mView).showIcon( + eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), isNull()); + } + + @Test + public void testOnViewAttachedShowsPriorityModeIconWhenEnabled() { + when(mZenModeController.getZen()).thenReturn( + Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); + mController.onViewAttached(); + verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true); + } + + @Test + public void testOnViewAttachedHidesPriorityModeIconWhenDisabled() { + when(mZenModeController.getZen()).thenReturn( + Settings.Global.ZEN_MODE_OFF); + mController.onViewAttached(); + verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false); } @Test @@ -103,10 +230,19 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { } @Test - public void testWifiStatusHiddenWhenWifiBecomesAvailable() { - // Make sure wifi starts out unavailable when onViewAttached is called. + public void testOnViewDetachedRemovesCallbacks() { + mController.onViewDetached(); + verify(mNextAlarmController).removeCallback(any()); + verify(mSensorPrivacyController).removeCallback(any()); + verify(mZenModeController).removeCallback(any()); + } + + @Test + public void testWifiIconHiddenWhenWifiBecomesAvailable() { + // Make sure wifi starts out unavailable when onViewAttached is called, and then returns + // true on the second query. when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) - .thenReturn(false); + .thenReturn(false).thenReturn(true); when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities); mController.onViewAttached(); @@ -114,14 +250,15 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class); verify(mConnectivityManager).registerNetworkCallback(any(), callbackCapture.capture()); callbackCapture.getValue().onAvailable(mNetwork); - verify(mView).showWifiStatus(false); + verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false); } @Test - public void testWifiStatusShownWhenWifiBecomesUnavailable() { - // Make sure wifi starts out available when onViewAttached is called. + public void testWifiIconShownWhenWifiBecomesUnavailable() { + // Make sure wifi starts out available when onViewAttached is called, then returns false + // on the second query. when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) - .thenReturn(true); + .thenReturn(true).thenReturn(false); when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities); mController.onViewAttached(); @@ -129,11 +266,11 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class); verify(mConnectivityManager).registerNetworkCallback(any(), callbackCapture.capture()); callbackCapture.getValue().onLost(mNetwork); - verify(mView).showWifiStatus(true); + verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true); } @Test - public void testWifiStatusHiddenWhenCapabilitiesChange() { + public void testWifiIconHiddenWhenCapabilitiesChange() { // Make sure wifi starts out unavailable when onViewAttached is called. when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) .thenReturn(false); @@ -146,6 +283,102 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) .thenReturn(true); callbackCapture.getValue().onCapabilitiesChanged(mNetwork, mNetworkCapabilities); - verify(mView).showWifiStatus(false); + verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false); + } + + @Test + public void testNotificationsIconShownWhenNotificationAdded() { + mController.onViewAttached(); + + StatusBarNotification[] notifications = { mStatusBarNotification }; + when(mNotificationListener.getActiveNotifications()).thenReturn(notifications); + + final ArgumentCaptor<NotificationListener.NotificationHandler> callbackCapture = + ArgumentCaptor.forClass(NotificationListener.NotificationHandler.class); + verify(mNotificationListener).addNotificationHandler(callbackCapture.capture()); + callbackCapture.getValue().onNotificationPosted(mStatusBarNotification, mRankingMap); + + verify(mView).showIcon( + eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any()); + } + + @Test + public void testNotificationsIconHiddenWhenLastNotificationRemoved() { + StatusBarNotification[] notifications = { mStatusBarNotification }; + when(mNotificationListener.getActiveNotifications()).thenReturn(notifications) + .thenReturn(null); + mController.onViewAttached(); + + final ArgumentCaptor<NotificationListener.NotificationHandler> callbackCapture = + ArgumentCaptor.forClass(NotificationListener.NotificationHandler.class); + verify(mNotificationListener).addNotificationHandler(callbackCapture.capture()); + callbackCapture.getValue().onNotificationPosted(mStatusBarNotification, mRankingMap); + + verify(mView).showIcon( + eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), any()); + } + + @Test + public void testMicCameraIconShownWhenSensorsBlocked() { + mController.onViewAttached(); + + when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE)) + .thenReturn(true); + when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA)) + .thenReturn(true); + + final ArgumentCaptor<IndividualSensorPrivacyController.Callback> callbackCapture = + ArgumentCaptor.forClass(IndividualSensorPrivacyController.Callback.class); + verify(mSensorPrivacyController).addCallback(callbackCapture.capture()); + callbackCapture.getValue().onSensorBlockedChanged( + SensorPrivacyManager.Sensors.MICROPHONE, true); + + verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true); + } + + @Test + public void testMicCameraIconHiddenWhenSensorsNotBlocked() { + when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE)) + .thenReturn(true).thenReturn(false); + when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA)) + .thenReturn(true).thenReturn(false); + mController.onViewAttached(); + + final ArgumentCaptor<IndividualSensorPrivacyController.Callback> callbackCapture = + ArgumentCaptor.forClass(IndividualSensorPrivacyController.Callback.class); + verify(mSensorPrivacyController).addCallback(callbackCapture.capture()); + callbackCapture.getValue().onSensorBlockedChanged( + SensorPrivacyManager.Sensors.MICROPHONE, false); + + verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false); + } + + @Test + public void testPriorityModeIconShownWhenZenModeEnabled() { + mController.onViewAttached(); + + when(mZenModeController.getZen()).thenReturn(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS); + + final ArgumentCaptor<ZenModeController.Callback> callbackCapture = + ArgumentCaptor.forClass(ZenModeController.Callback.class); + verify(mZenModeController).addCallback(callbackCapture.capture()); + callbackCapture.getValue().onZenChanged(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS); + + verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true); + } + + @Test + public void testPriorityModeIconHiddenWhenZenModeDisabled() { + when(mZenModeController.getZen()).thenReturn(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS) + .thenReturn(Settings.Global.ZEN_MODE_OFF); + mController.onViewAttached(); + + + final ArgumentCaptor<ZenModeController.Callback> callbackCapture = + ArgumentCaptor.forClass(ZenModeController.Callback.class); + verify(mZenModeController).addCallback(callbackCapture.capture()); + callbackCapture.getValue().onZenChanged(Settings.Global.ZEN_MODE_OFF); + + verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, 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 cad98f4dc713..6e01541c75e0 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 @@ -18,7 +18,6 @@ package com.android.systemui.dreams.touch; import static com.google.common.truth.Truth.assertThat; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyFloat; @@ -27,19 +26,21 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.animation.ValueAnimator; +import android.graphics.Rect; +import android.graphics.Region; import android.testing.AndroidTestingRunner; +import android.util.DisplayMetrics; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.VelocityTracker; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.shared.system.InputChannelCompat; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.KeyguardBouncer; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.wm.shell.animation.FlingAnimationUtils; @@ -51,8 +52,6 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -import java.util.Random; - @SmallTest @RunWith(AndroidTestingRunner.class) public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { @@ -60,7 +59,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock - StatusBar mStatusBar; + CentralSurfaces mCentralSurfaces; @Mock NotificationShadeWindowController mNotificationShadeWindowController; @@ -89,38 +88,51 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { @Mock VelocityTracker mVelocityTracker; + final DisplayMetrics mDisplayMetrics = new DisplayMetrics(); + private static final float TOUCH_REGION = .3f; - private static final float SCREEN_HEIGHT_PX = 100; + private static final int SCREEN_WIDTH_PX = 1024; + private static final int SCREEN_HEIGHT_PX = 100; @Before public void setup() { + mDisplayMetrics.widthPixels = SCREEN_WIDTH_PX; + mDisplayMetrics.heightPixels = SCREEN_HEIGHT_PX; + MockitoAnnotations.initMocks(this); mTouchHandler = new BouncerSwipeTouchHandler( + mDisplayMetrics, mStatusBarKeyguardViewManager, - mStatusBar, + mCentralSurfaces, mNotificationShadeWindowController, mValueAnimatorCreator, mVelocityTrackerFactory, mFlingAnimationUtils, mFlingAnimationUtilsClosing, TOUCH_REGION); - when(mStatusBar.getDisplayHeight()).thenReturn(SCREEN_HEIGHT_PX); + + when(mCentralSurfaces.getDisplayHeight()).thenReturn((float) SCREEN_HEIGHT_PX); when(mValueAnimatorCreator.create(anyFloat(), anyFloat())).thenReturn(mValueAnimator); when(mVelocityTrackerFactory.obtain()).thenReturn(mVelocityTracker); } - private static void beginValidSwipe(GestureDetector.OnGestureListener listener) { - listener.onDown(MotionEvent.obtain(0, 0, - MotionEvent.ACTION_DOWN, 0, - SCREEN_HEIGHT_PX - (.5f * TOUCH_REGION * SCREEN_HEIGHT_PX), 0)); - } - /** * Ensures expansion only happens when touch down happens in valid part of the screen. */ - @FlakyTest @Test public void testSessionStart() { + final Region region = Region.obtain(); + mTouchHandler.getTouchInitiationRegion(region); + + final Rect bounds = region.getBounds(); + + final Rect expected = new Rect(); + + expected.set(0, Math.round(SCREEN_HEIGHT_PX * (1 - TOUCH_REGION)), SCREEN_WIDTH_PX, + SCREEN_HEIGHT_PX); + + assertThat(bounds).isEqualTo(expected); + mTouchHandler.onSessionStart(mTouchSession); verify(mNotificationShadeWindowController).setForcePluginOpen(eq(true), any()); ArgumentCaptor<InputChannelCompat.InputEventListener> eventListenerCaptor = @@ -130,34 +142,12 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture()); verify(mTouchSession).registerInputListener(eventListenerCaptor.capture()); - final Random random = new Random(System.currentTimeMillis()); - - // If an initial touch down meeting criteria has been met, scroll behavior should be - // ignored. - assertThat(gestureListenerCaptor.getValue() - .onScroll(Mockito.mock(MotionEvent.class), - Mockito.mock(MotionEvent.class), - random.nextFloat(), - random.nextFloat())).isFalse(); - - // A touch at the top of the screen should also not trigger listening. - final MotionEvent touchDownEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, - 0, 0, 0); - - gestureListenerCaptor.getValue().onDown(touchDownEvent); - assertThat(gestureListenerCaptor.getValue() - .onScroll(Mockito.mock(MotionEvent.class), - Mockito.mock(MotionEvent.class), - random.nextFloat(), - random.nextFloat())).isFalse(); - // A touch within range at the bottom of the screen should trigger listening - beginValidSwipe(gestureListenerCaptor.getValue()); assertThat(gestureListenerCaptor.getValue() .onScroll(Mockito.mock(MotionEvent.class), Mockito.mock(MotionEvent.class), - random.nextFloat(), - random.nextFloat())).isTrue(); + 1, + 2)).isTrue(); } /** @@ -170,8 +160,6 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class); verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture()); - beginValidSwipe(gestureListenerCaptor.getValue()); - final float scrollAmount = .3f; final float distanceY = SCREEN_HEIGHT_PX * scrollAmount; @@ -203,8 +191,6 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { when(mVelocityTracker.getYVelocity()).thenReturn(velocityY); - beginValidSwipe(gestureListenerCaptor.getValue()); - final float distanceY = SCREEN_HEIGHT_PX * position; final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java index 74b217b2fdbf..29f56e0d8bf0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java @@ -21,10 +21,13 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.graphics.Rect; +import android.graphics.Region; import android.testing.AndroidTestingRunner; import android.util.Pair; import android.view.GestureDetector; @@ -137,6 +140,81 @@ public class DreamOverlayTouchMonitorTest extends SysuiTestCase { } @Test + public void testEntryTouchZone() { + final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); + final Rect touchArea = new Rect(4, 4, 8 , 8); + + doAnswer(invocation -> { + final Region region = (Region) invocation.getArguments()[0]; + region.set(touchArea); + return null; + }).when(touchHandler).getTouchInitiationRegion(any()); + + final Environment environment = new Environment(Stream.of(touchHandler) + .collect(Collectors.toCollection(HashSet::new))); + + // Ensure touch outside specified region is not delivered. + final MotionEvent initialEvent = Mockito.mock(MotionEvent.class); + when(initialEvent.getX()).thenReturn(0.0f); + when(initialEvent.getY()).thenReturn(1.0f); + environment.publishInputEvent(initialEvent); + verify(touchHandler, never()).onSessionStart(any()); + + // Make sure touch inside region causes session start. + when(initialEvent.getX()).thenReturn(5.0f); + when(initialEvent.getY()).thenReturn(5.0f); + environment.publishInputEvent(initialEvent); + verify(touchHandler).onSessionStart(any()); + } + + @Test + public void testSessionCount() { + final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); + final Rect touchArea = new Rect(4, 4, 8 , 8); + + final DreamTouchHandler unzonedTouchHandler = Mockito.mock(DreamTouchHandler.class); + doAnswer(invocation -> { + final Region region = (Region) invocation.getArguments()[0]; + region.set(touchArea); + return null; + }).when(touchHandler).getTouchInitiationRegion(any()); + + final Environment environment = new Environment(Stream.of(touchHandler, unzonedTouchHandler) + .collect(Collectors.toCollection(HashSet::new))); + + // Ensure touch outside specified region is delivered to unzoned touch handler. + final MotionEvent initialEvent = Mockito.mock(MotionEvent.class); + when(initialEvent.getX()).thenReturn(0.0f); + when(initialEvent.getY()).thenReturn(1.0f); + environment.publishInputEvent(initialEvent); + + ArgumentCaptor<DreamTouchHandler.TouchSession> touchSessionCaptor = ArgumentCaptor.forClass( + DreamTouchHandler.TouchSession.class); + + // Make sure only one active session. + { + verify(unzonedTouchHandler).onSessionStart(touchSessionCaptor.capture()); + final DreamTouchHandler.TouchSession touchSession = touchSessionCaptor.getValue(); + assertThat(touchSession.getActiveSessionCount()).isEqualTo(1); + touchSession.pop(); + environment.executeAll(); + } + + // Make sure touch inside the touch region. + when(initialEvent.getX()).thenReturn(5.0f); + when(initialEvent.getY()).thenReturn(5.0f); + environment.publishInputEvent(initialEvent); + + // Make sure there are two active sessions. + { + verify(touchHandler).onSessionStart(touchSessionCaptor.capture()); + final DreamTouchHandler.TouchSession touchSession = touchSessionCaptor.getValue(); + assertThat(touchSession.getActiveSessionCount()).isEqualTo(2); + touchSession.pop(); + } + } + + @Test public void testInputEventPropagation() { final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java index 953be7d6f002..6fead9efa767 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java @@ -60,7 +60,7 @@ import com.android.systemui.plugins.GlobalActions; import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.VibratorHelper; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.telephony.TelephonyListenerManager; @@ -113,7 +113,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { @Mock private Handler mHandler; @Mock private UserContextProvider mUserContextProvider; @Mock private VibratorHelper mVibratorHelper; - @Mock private StatusBar mStatusBar; + @Mock private CentralSurfaces mCentralSurfaces; @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock private DialogLaunchAnimator mDialogLaunchAnimator; @@ -158,7 +158,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { mRingerModeTracker, mHandler, mPackageManager, - Optional.of(mStatusBar), + Optional.of(mCentralSurfaces), mKeyguardUpdateMonitor, mDialogLaunchAnimator); mGlobalActionsDialogLite.setZeroDialogPressDelayForTesting(); @@ -227,7 +227,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems(); doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any()); doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any()); - doReturn(true).when(mStatusBar).isKeyguardShowing(); + doReturn(true).when(mCentralSurfaces).isKeyguardShowing(); String[] actions = { GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY, GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN, @@ -242,7 +242,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { MotionEvent end = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 500, 0); gestureListener.onFling(start, end, 0, 1000); verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE); - verify(mStatusBar).animateExpandSettingsPanel(null); + verify(mCentralSurfaces).animateExpandSettingsPanel(null); } @Test @@ -251,7 +251,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems(); doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any()); doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any()); - doReturn(false).when(mStatusBar).isKeyguardShowing(); + doReturn(false).when(mCentralSurfaces).isKeyguardShowing(); String[] actions = { GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY, GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN, @@ -266,7 +266,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { MotionEvent end = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 500, 0); gestureListener.onFling(start, end, 0, 1000); verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE); - verify(mStatusBar).animateExpandNotificationsPanel(); + verify(mCentralSurfaces).animateExpandNotificationsPanel(); } @Test @@ -432,7 +432,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems(); doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any()); doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any()); - doReturn(false).when(mStatusBar).isKeyguardShowing(); + doReturn(false).when(mCentralSurfaces).isKeyguardShowing(); String[] actions = { GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY, GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN, diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt index e606be179cc6..b359ae5317b1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt @@ -33,10 +33,11 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.phone.KeyguardBypassController -import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.FakeConfigurationController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.animation.UniqueObjectHostView -import junit.framework.Assert +import com.android.systemui.util.mockito.any +import com.google.common.truth.Truth.assertThat import org.junit.Assert.assertNotNull import org.junit.Before import org.junit.Rule @@ -44,16 +45,16 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers +import org.mockito.ArgumentMatchers.anyBoolean +import org.mockito.ArgumentMatchers.anyLong import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.`when` -import org.mockito.Mockito.any -import org.mockito.Mockito.anyBoolean -import org.mockito.Mockito.anyLong import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit +import org.mockito.Mockito.`when` as whenever @SmallTest @RunWith(AndroidTestingRunner::class) @@ -83,8 +84,6 @@ class MediaHierarchyManagerTest : SysuiTestCase() { @Mock private lateinit var keyguardViewController: KeyguardViewController @Mock - private lateinit var configurationController: ConfigurationController - @Mock private lateinit var uniqueObjectHostView: UniqueObjectHostView @Mock private lateinit var dreamOverlayStateController: DreamOverlayStateController @@ -97,6 +96,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { val mockito = MockitoJUnit.rule() private lateinit var mediaHiearchyManager: MediaHierarchyManager private lateinit var mediaFrame: ViewGroup + private val configurationController = FakeConfigurationController() @Before fun setup() { @@ -176,12 +176,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { @Test fun testGoingToFullShade() { - // Let's set it onto Lock screen - `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) - `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn( - true) - statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD) - clearInvocations(mediaCarouselController) + goToLockscreen() // Let's transition all the way to full shade mediaHiearchyManager.setTransitionToFullShadeAmount(100000f) @@ -204,41 +199,48 @@ class MediaHierarchyManagerTest : SysuiTestCase() { // Let's make sure alpha is set mediaHiearchyManager.setTransitionToFullShadeAmount(2.0f) - Assert.assertTrue("alpha should not be 1.0f when cross fading", mediaFrame.alpha != 1.0f) + assertThat(mediaFrame.alpha).isNotEqualTo(1.0f) } @Test fun testTransformationOnLockScreenIsFading() { - // Let's set it onto Lock screen - `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) - `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn( - true) - statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD) - clearInvocations(mediaCarouselController) + goToLockscreen() + expandQS() + + val transformType = mediaHiearchyManager.calculateTransformationType() + assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE) + } + + @Test + fun calculateTransformationType_onLockShade_inSplitShade_goingToFullShade_returnsTransition() { + enableSplitShade() + goToLockscreen() + expandQS() + mediaHiearchyManager.setTransitionToFullShadeAmount(10000f) + + val transformType = mediaHiearchyManager.calculateTransformationType() + assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION) + } + + @Test + fun calculateTransformationType_onLockShade_inSplitShade_notExpanding_returnsFade() { + enableSplitShade() + goToLockscreen() + goToLockedShade() + expandQS() + mediaHiearchyManager.setTransitionToFullShadeAmount(0f) - // Let's transition from lockscreen to qs - mediaHiearchyManager.qsExpansion = 1.0f val transformType = mediaHiearchyManager.calculateTransformationType() - Assert.assertTrue("media isn't transforming to qs with a fade", - transformType == MediaHierarchyManager.TRANSFORMATION_TYPE_FADE) + assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE) } @Test fun testTransformationOnLockScreenToQQSisFading() { - // Let's set it onto Lock screen - `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) - `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn( - true) - statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD) - clearInvocations(mediaCarouselController) + goToLockscreen() + goToLockedShade() - // Let's transition from lockscreen to qs - `when`(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED) - statusBarCallback.value.onStatePreChange(StatusBarState.KEYGUARD, - StatusBarState.SHADE_LOCKED) val transformType = mediaHiearchyManager.calculateTransformationType() - Assert.assertTrue("media isn't transforming to qqswith a fade", - transformType == MediaHierarchyManager.TRANSFORMATION_TYPE_FADE) + assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE) } @Test @@ -254,4 +256,32 @@ class MediaHierarchyManagerTest : SysuiTestCase() { verify(mediaCarouselController).closeGuts() } -}
\ No newline at end of file + + private fun enableSplitShade() { + context.getOrCreateTestableResources().addOverride( + R.bool.config_use_split_notification_shade, true + ) + configurationController.notifyConfigurationChanged() + } + + private fun goToLockscreen() { + whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn( + true + ) + statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD) + clearInvocations(mediaCarouselController) + } + + private fun goToLockedShade() { + whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED) + statusBarCallback.value.onStatePreChange( + StatusBarState.KEYGUARD, + StatusBarState.SHADE_LOCKED + ) + } + + private fun expandQS() { + mediaHiearchyManager.qsExpansion = 1.0f + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt index 28de17664df1..809b8901f867 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.media.taptotransfer.common import android.content.Context import android.graphics.drawable.Drawable +import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.view.WindowManager @@ -30,7 +31,10 @@ import com.android.systemui.statusbar.gesture.TapGestureDetector import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.argumentCaptor +import com.android.systemui.util.mockito.capture import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.util.view.ViewUtil import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test @@ -39,6 +43,7 @@ import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations @SmallTest @@ -52,6 +57,8 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { @Mock private lateinit var windowManager: WindowManager @Mock + private lateinit var viewUtil: ViewUtil + @Mock private lateinit var tapGestureDetector: TapGestureDetector @Before @@ -62,7 +69,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { fakeExecutor = FakeExecutor(fakeClock) controllerCommon = TestControllerCommon( - context, windowManager, fakeExecutor, tapGestureDetector + context, windowManager, viewUtil, fakeExecutor, tapGestureDetector ) } @@ -169,6 +176,40 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { .isEqualTo(state.getAppName(context)) } + @Test + fun tapGestureDetected_outsideViewBounds_viewHidden() { + controllerCommon.displayChip(getState()) + whenever(viewUtil.touchIsWithinView(any(), any(), any())).thenReturn(false) + val gestureCallbackCaptor = argumentCaptor<(MotionEvent) -> Unit>() + verify(tapGestureDetector).addOnGestureDetectedCallback( + any(), capture(gestureCallbackCaptor) + ) + val callback = gestureCallbackCaptor.value!! + + callback.invoke( + MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0f, 0f, 0) + ) + + verify(windowManager).removeView(any()) + } + + @Test + fun tapGestureDetected_insideViewBounds_viewNotHidden() { + controllerCommon.displayChip(getState()) + whenever(viewUtil.touchIsWithinView(any(), any(), any())).thenReturn(true) + val gestureCallbackCaptor = argumentCaptor<(MotionEvent) -> Unit>() + verify(tapGestureDetector).addOnGestureDetectedCallback( + any(), capture(gestureCallbackCaptor) + ) + val callback = gestureCallbackCaptor.value!! + + callback.invoke( + MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0f, 0f, 0) + ) + + verify(windowManager, never()).removeView(any()) + } + private fun getState() = MediaTttChipState(PACKAGE_NAME) private fun getChipView(): ViewGroup { @@ -182,10 +223,11 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { inner class TestControllerCommon( context: Context, windowManager: WindowManager, + viewUtil: ViewUtil, @Main mainExecutor: DelayableExecutor, tapGestureDetector: TapGestureDetector, ) : MediaTttChipControllerCommon<MediaTttChipState>( - context, windowManager, mainExecutor, tapGestureDetector, R.layout.media_ttt_chip + context, windowManager, viewUtil, mainExecutor, tapGestureDetector, R.layout.media_ttt_chip ) { override fun updateChipView(chipState: MediaTttChipState, currentChipView: ViewGroup) { } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt index e5f4df6c622a..86d4c1b05ed3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt @@ -37,6 +37,7 @@ import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.util.view.ViewUtil import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test @@ -61,6 +62,8 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { @Mock private lateinit var windowManager: WindowManager @Mock + private lateinit var viewUtil: ViewUtil + @Mock private lateinit var commandQueue: CommandQueue private lateinit var commandQueueCallback: CommandQueue.Callbacks private lateinit var fakeAppIconDrawable: Drawable @@ -81,6 +84,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { commandQueue, context, windowManager, + viewUtil, FakeExecutor(FakeSystemClock()), TapGestureDetector(context), Handler.getMain(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt index e5ba3f3d87bf..88888f0da0f7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt @@ -38,6 +38,8 @@ import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.util.view.ViewUtil + import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test @@ -62,6 +64,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { @Mock private lateinit var windowManager: WindowManager @Mock + private lateinit var viewUtil: ViewUtil + @Mock private lateinit var commandQueue: CommandQueue private lateinit var commandQueueCallback: CommandQueue.Callbacks private lateinit var fakeAppIconDrawable: Drawable @@ -82,6 +86,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { commandQueue, context, windowManager, + viewUtil, FakeExecutor(FakeSystemClock()), TapGestureDetector(context) ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java index 3a95ed3da84d..634d9e4642b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java @@ -37,8 +37,7 @@ import com.android.systemui.assist.AssistManager; import com.android.systemui.dump.DumpManager; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.settings.UserTracker; -import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; +import com.android.systemui.statusbar.phone.CentralSurfaces; import org.junit.Before; import org.junit.Test; @@ -91,7 +90,7 @@ public class NavBarHelperTest extends SysuiTestCase { mNavBarHelper = new NavBarHelper(mContext, mAccessibilityManager, mAccessibilityButtonModeObserver, mAccessibilityButtonTargetObserver, mSystemActions, mOverviewProxyService, mAssistManagerLazy, - () -> Optional.of(mock(StatusBar.class)), + () -> Optional.of(mock(CentralSurfaces.class)), mNavigationModeController, mUserTracker, mDumpManager); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java index 5a652fc15a48..eb1e1a2e3d04 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java @@ -94,7 +94,7 @@ import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.NotificationShadeWindowView; import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.utils.leaks.LeakCheckedTest; @@ -160,7 +160,7 @@ public class NavigationBarTest extends SysuiTestCase { @Mock private AssistManager mAssistManager; @Mock - private StatusBar mStatusBar; + private CentralSurfaces mCentralSurfaces; @Rule public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck(); @@ -189,7 +189,7 @@ public class NavigationBarTest extends SysuiTestCase { mock(AccessibilityButtonModeObserver.class), mock(AccessibilityButtonTargetsObserver.class), mSystemActions, mOverviewProxyService, - () -> mock(AssistManager.class), () -> Optional.of(mStatusBar), + () -> mock(AssistManager.class), () -> Optional.of(mCentralSurfaces), mock(NavigationModeController.class), mock(UserTracker.class), mock(DumpManager.class))); mNavigationBar = createNavBar(mContext); @@ -282,7 +282,7 @@ public class NavigationBarTest extends SysuiTestCase { NotificationShadeWindowView mockShadeWindowView = mock(NotificationShadeWindowView.class); WindowInsets windowInsets = new WindowInsets.Builder().setVisible(ime(), false).build(); doReturn(windowInsets).when(mockShadeWindowView).getRootWindowInsets(); - doReturn(mockShadeWindowView).when(mStatusBar).getNotificationShadeWindowView(); + doReturn(mockShadeWindowView).when(mCentralSurfaces).getNotificationShadeWindowView(); doReturn(true).when(mockShadeWindowView).isAttachedToWindow(); doNothing().when(defaultNavBar).checkNavBarModes(); doNothing().when(externalNavBar).checkNavBarModes(); @@ -318,7 +318,7 @@ public class NavigationBarTest extends SysuiTestCase { @Test public void testSetImeWindowStatusWhenKeyguardLockingAndImeInsetsChange() { NotificationShadeWindowView mockShadeWindowView = mock(NotificationShadeWindowView.class); - doReturn(mockShadeWindowView).when(mStatusBar).getNotificationShadeWindowView(); + doReturn(mockShadeWindowView).when(mCentralSurfaces).getNotificationShadeWindowView(); doReturn(true).when(mockShadeWindowView).isAttachedToWindow(); doNothing().when(mNavigationBar).checkNavBarModes(); mNavigationBar.createView(null, /* initialVisibility= */ true); @@ -335,7 +335,7 @@ public class NavigationBarTest extends SysuiTestCase { // Verify navbar didn't alter and showing back icon when the keyguard is showing without // requesting IME insets visible. - doReturn(true).when(mStatusBar).isKeyguardShowing(); + doReturn(true).when(mCentralSurfaces).isKeyguardShowing(); mNavigationBar.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true); assertFalse((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); @@ -401,7 +401,7 @@ public class NavigationBarTest extends SysuiTestCase { mCommandQueue, Optional.of(mock(Pip.class)), Optional.of(mock(Recents.class)), - () -> Optional.of(mStatusBar), + () -> Optional.of(mCentralSurfaces), mock(ShadeController.class), mock(NotificationRemoteInputManager.class), mock(NotificationShadeDepthController.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java index 721809c83cd8..91f8a403f3b5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java @@ -48,7 +48,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.power.PowerUI.WarningsUI; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import org.junit.Before; import org.junit.Test; @@ -89,14 +89,14 @@ public class PowerUITest extends SysuiTestCase { private IThermalEventListener mSkinThermalEventListener; @Mock private BroadcastDispatcher mBroadcastDispatcher; @Mock private CommandQueue mCommandQueue; - @Mock private Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; - @Mock private StatusBar mStatusBar; + @Mock private Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; + @Mock private CentralSurfaces mCentralSurfaces; @Before public void setup() { MockitoAnnotations.initMocks(this); - when(mStatusBarOptionalLazy.get()).thenReturn(Optional.of(mStatusBar)); + when(mCentralSurfacesOptionalLazy.get()).thenReturn(Optional.of(mCentralSurfaces)); createPowerUi(); mSkinThermalEventListener = mPowerUI.new SkinThermalEventListener(); @@ -430,12 +430,6 @@ public class PowerUITest extends SysuiTestCase { state.mIsPowerSaver = true; shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); assertThat(shouldShow).isFalse(); - - state.mIsPowerSaver = false; - // if disabled we should not show the low warning. - state.mIsLowLevelWarningEnabled = false; - shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); - assertThat(shouldShow).isFalse(); } @Test @@ -685,7 +679,7 @@ public class PowerUITest extends SysuiTestCase { private void createPowerUi() { mPowerUI = new PowerUI( - mContext, mBroadcastDispatcher, mCommandQueue, mStatusBarOptionalLazy, + mContext, mBroadcastDispatcher, mCommandQueue, mCentralSurfacesOptionalLazy, mMockWarnings, mEnhancedEstimates, mPowerManager); mPowerUI.mThermalService = mThermalServiceMock; } 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 4ab39261e825..534c7e7f2029 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -56,7 +56,7 @@ import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.policy.Clock; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -142,7 +142,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { 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(StatusBar.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)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index 8872e28647a7..e67d37ac3c72 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -65,7 +65,7 @@ import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.phone.AutoTileManager; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.tuner.TunerService; import com.android.systemui.util.settings.FakeSettings; @@ -112,7 +112,7 @@ public class QSTileHostTest extends SysuiTestCase { @Mock private QSTile.State mMockState; @Mock - private StatusBar mStatusBar; + private CentralSurfaces mCentralSurfaces; @Mock private QSLogger mQSLogger; @Mock @@ -152,7 +152,7 @@ public class QSTileHostTest extends SysuiTestCase { QSTileHost.TILES_SETTING, "", "", false, mUserTracker.getUserId(), false); mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler, mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager, - mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker, + mBroadcastDispatcher, mCentralSurfaces, mQSLogger, mUiEventLogger, mUserTracker, mSecureSettings, mCustomTileStatePersister, mTileServiceRequestControllerBuilder, mTileLifecycleManagerFactory); setUpTileFactory(); @@ -437,15 +437,15 @@ public class QSTileHostTest extends SysuiTestCase { QSFactory defaultFactory, Handler mainHandler, Looper bgLooper, PluginManager pluginManager, TunerService tunerService, Provider<AutoTileManager> autoTiles, DumpManager dumpManager, - BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger, - UiEventLogger uiEventLogger, UserTracker userTracker, + BroadcastDispatcher broadcastDispatcher, CentralSurfaces centralSurfaces, + QSLogger qsLogger, UiEventLogger uiEventLogger, UserTracker userTracker, SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister, TileServiceRequestController.Builder tileServiceRequestControllerBuilder, TileLifecycleManager.Factory tileLifecycleManagerFactory) { super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager, tunerService, autoTiles, dumpManager, broadcastDispatcher, - Optional.of(statusBar), qsLogger, uiEventLogger, userTracker, secureSettings, - customTileStatePersister, tileServiceRequestControllerBuilder, + Optional.of(centralSurfaces), qsLogger, uiEventLogger, userTracker, + secureSettings, customTileStatePersister, tileServiceRequestControllerBuilder, tileLifecycleManagerFactory); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java index e39d6a1bfc01..19a9863f6f5e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java @@ -50,7 +50,7 @@ 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.phone.AutoTileManager; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.policy.BluetoothController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -91,7 +91,7 @@ public class TileServicesTest extends SysuiTestCase { @Mock private DumpManager mDumpManager; @Mock - private StatusBar mStatusBar; + private CentralSurfaces mCentralSurfaces; @Mock private QSLogger mQSLogger; @Mock @@ -132,7 +132,7 @@ public class TileServicesTest extends SysuiTestCase { () -> mAutoTileManager, mDumpManager, mock(BroadcastDispatcher.class), - Optional.of(mStatusBar), + Optional.of(mCentralSurfaces), mQSLogger, mUiEventLogger, mUserTracker, diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java index bfe875ccd60d..7ab49584f0e3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java @@ -19,7 +19,7 @@ package com.android.systemui.screenshot; import static com.android.systemui.screenshot.ScreenshotController.ACTION_TYPE_SHARE; import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ID; import static com.android.systemui.screenshot.ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED; -import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT; +import static com.android.systemui.statusbar.phone.CentralSurfaces.SYSTEM_DIALOG_REASON_SCREENSHOT; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -41,7 +41,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import org.junit.Before; import org.junit.Test; @@ -59,7 +59,7 @@ import java.util.concurrent.TimeoutException; public class ActionProxyReceiverTest extends SysuiTestCase { @Mock - private StatusBar mMockStatusBar; + private CentralSurfaces mMockCentralSurfaces; @Mock private ActivityManagerWrapper mMockActivityManagerWrapper; @Mock @@ -83,7 +83,7 @@ public class ActionProxyReceiverTest extends SysuiTestCase { actionProxyReceiver.onReceive(mContext, mIntent); verify(mMockActivityManagerWrapper).closeSystemWindows(SYSTEM_DIALOG_REASON_SCREENSHOT); - verify(mMockStatusBar, never()).executeRunnableDismissingKeyguard( + verify(mMockCentralSurfaces, never()).executeRunnableDismissingKeyguard( any(Runnable.class), any(Runnable.class), anyBoolean(), anyBoolean(), anyBoolean()); verify(mMockPendingIntent).send( eq(mContext), anyInt(), isNull(), isNull(), isNull(), isNull(), any(Bundle.class)); @@ -96,13 +96,13 @@ public class ActionProxyReceiverTest extends SysuiTestCase { doAnswer((Answer<Object>) invocation -> { ((Runnable) invocation.getArgument(0)).run(); return null; - }).when(mMockStatusBar).executeRunnableDismissingKeyguard( + }).when(mMockCentralSurfaces).executeRunnableDismissingKeyguard( any(Runnable.class), isNull(), anyBoolean(), anyBoolean(), anyBoolean()); actionProxyReceiver.onReceive(mContext, mIntent); verify(mMockActivityManagerWrapper).closeSystemWindows(SYSTEM_DIALOG_REASON_SCREENSHOT); - verify(mMockStatusBar).executeRunnableDismissingKeyguard( + verify(mMockCentralSurfaces).executeRunnableDismissingKeyguard( any(Runnable.class), isNull(), eq(true), eq(true), eq(true)); verify(mMockPendingIntent).send( eq(mContext), anyInt(), isNull(), isNull(), isNull(), isNull(), any(Bundle.class)); @@ -135,7 +135,7 @@ public class ActionProxyReceiverTest extends SysuiTestCase { private ActionProxyReceiver constructActionProxyReceiver(boolean withStatusBar) { if (withStatusBar) { return new ActionProxyReceiver( - Optional.of(mMockStatusBar), mMockActivityManagerWrapper, + Optional.of(mMockCentralSurfaces), mMockActivityManagerWrapper, mMockScreenshotSmartActions); } else { return new ActionProxyReceiver( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt index 9076e1607be5..25a5b900f15a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt @@ -22,8 +22,8 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.LSShadeTransitionLogger import com.android.systemui.statusbar.phone.NotificationPanelViewController import com.android.systemui.statusbar.phone.ScrimController -import com.android.systemui.statusbar.phone.StatusBar -import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.phone.CentralSurfaces +import com.android.systemui.statusbar.policy.FakeConfigurationController import org.junit.After import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull @@ -66,17 +66,18 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { @Mock lateinit var wakefulnessLifecycle: WakefulnessLifecycle @Mock lateinit var mediaHierarchyManager: MediaHierarchyManager @Mock lateinit var scrimController: ScrimController - @Mock lateinit var configurationController: ConfigurationController @Mock lateinit var falsingManager: FalsingManager @Mock lateinit var notificationPanelController: NotificationPanelViewController @Mock lateinit var nsslController: NotificationStackScrollLayoutController @Mock lateinit var depthController: NotificationShadeDepthController @Mock lateinit var stackscroller: NotificationStackScrollLayout @Mock lateinit var expandHelperCallback: ExpandHelper.Callback - @Mock lateinit var statusbar: StatusBar + @Mock lateinit var mCentralSurfaces: CentralSurfaces @Mock lateinit var qS: QS @JvmField @Rule val mockito = MockitoJUnit.rule() + private val configurationController = FakeConfigurationController() + @Before fun setup() { val helper = NotificationTestHelper( @@ -105,7 +106,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { whenever(nsslController.view).thenReturn(stackscroller) whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback) transitionController.notificationPanelController = notificationPanelController - transitionController.statusbar = statusbar + transitionController.centralSurfaces = mCentralSurfaces transitionController.qS = qS transitionController.setStackScroller(nsslController) whenever(statusbarStateController.state).thenReturn(StatusBarState.KEYGUARD) @@ -117,7 +118,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { whenever(lockScreenUserManager.isLockscreenPublicMode(anyInt())).thenReturn(true) whenever(falsingCollector.shouldEnforceBouncer()).thenReturn(false) whenever(keyguardBypassController.bypassEnabled).thenReturn(false) - clearInvocations(statusbar) + clearInvocations(mCentralSurfaces) } @After @@ -174,7 +175,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { @Test fun testDontGoWhenShadeDisabled() { - whenever(statusbar.isShadeDisabled).thenReturn(true) + whenever(mCentralSurfaces.isShadeDisabled).thenReturn(true) transitionController.goToLockedShade(null) verify(statusbarStateController, never()).setState(anyInt()) } @@ -193,7 +194,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { transitionController.goToLockedShade(null) verify(statusbarStateController, never()).setState(anyInt()) verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true) - verify(statusbar).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject()) + verify(mCentralSurfaces).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject()) } @Test @@ -202,7 +203,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { transitionController.goToLockedShade(null) verify(statusbarStateController, never()).setState(anyInt()) verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true) - verify(statusbar).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject()) + verify(mCentralSurfaces).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject()) } @Test @@ -244,4 +245,27 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat()) verify(depthController).transitionToFullShadeProgress = anyFloat() } + + @Test + fun setDragDownAmount_setsValueOnMediaHierarchyManager() { + transitionController.dragDownAmount = 10f + + verify(mediaHierarchyManager).setTransitionToFullShadeAmount(10f) + } + + @Test + fun setDragDownAmount_inSplitShade_setsValueOnMediaHierarchyManager() { + enableSplitShade() + + transitionController.dragDownAmount = 10f + + verify(mediaHierarchyManager).setTransitionToFullShadeAmount(10f) + } + + private fun enableSplitShade() { + context.getOrCreateTestableResources().addOverride( + R.bool.config_use_split_notification_shade, true + ) + configurationController.notifyConfigurationChanged() + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java index 4213b070d0c2..a4ce9cd12f73 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java @@ -47,8 +47,8 @@ import org.mockito.MockitoAnnotations; /** * Verifies that particular sets of dependencies don't have dependencies on others. For example, - * code managing notifications shouldn't directly depend on StatusBar, since there are platforms - * which want to manage notifications, but don't use StatusBar. + * code managing notifications shouldn't directly depend on CentralSurfaces, since there are + * platforms which want to manage notifications, but don't use CentralSurfaces. */ @SmallTest @RunWith(AndroidTestingRunner.class) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java index bd9f91f45e25..2691ff98f4ee 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java @@ -49,7 +49,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.google.android.collect.Sets; @@ -105,7 +105,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { mVisibilityProvider, mEntryManager, mock(RemoteInputNotificationRebuilder.class), - () -> Optional.of(mock(StatusBar.class)), + () -> Optional.of(mock(CentralSurfaces.class)), mStateController, Handler.createAsync(Looper.myLooper()), mRemoteInputUriController, @@ -196,7 +196,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { NotificationVisibilityProvider visibilityProvider, NotificationEntryManager notificationEntryManager, RemoteInputNotificationRebuilder rebuilder, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, + Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, StatusBarStateController statusBarStateController, Handler mainHandler, RemoteInputUriController remoteInputUriController, @@ -211,7 +211,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { visibilityProvider, notificationEntryManager, rebuilder, - statusBarOptionalLazy, + centralSurfacesOptionalLazy, statusBarStateController, mainHandler, remoteInputUriController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java index 7fafb24317b7..407044b5378a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java @@ -54,7 +54,6 @@ import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; -import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -121,7 +120,6 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { mock(KeyguardBypassController.class), Optional.of(mock(Bubbles.class)), mock(DynamicPrivacyController.class), - mock(ForegroundServiceSectionController.class), mock(DynamicChildBindController.class), mock(LowPriorityInflationHelper.class), mock(AssistantFeedbackController.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java index e0689f3da081..3500e4d5f701 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java @@ -45,7 +45,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.policy.RemoteInputUriController; import org.junit.Before; @@ -103,7 +103,7 @@ public class SmartReplyControllerTest extends SysuiTestCase { mVisibilityProvider, mNotificationEntryManager, new RemoteInputNotificationRebuilder(mContext), - () -> Optional.of(mock(StatusBar.class)), + () -> Optional.of(mock(CentralSurfaces.class)), mStatusBarStateController, Handler.createAsync(Looper.myLooper()), mRemoteInputUriController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt index c0389034b4f2..ea066471a802 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt @@ -111,7 +111,7 @@ class GenericGestureDetectorTest : SysuiTestCase() { override fun onInputEvent(ev: InputEvent) { if (ev is MotionEvent && ev.x == CORRECT_X) { - onGestureDetected() + onGestureDetected(ev) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index f2b7bf515c45..0fff5f5b47e5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -201,7 +201,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase { () -> mNotificationRowBinder, () -> mRemoteInputManager, mLeakDetector, - mock(ForegroundServiceDismissalFeatureController.class), mock(IStatusBarService.class), NotifLiveDataStoreMocksKt.createNotifLiveDataStoreImplMock(), mock(DumpManager.class) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java index 52189e417017..7fc5ece670d4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java @@ -61,7 +61,6 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.SbnBuilder; import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.notification.ConversationNotificationProcessor; -import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotificationClicker; import com.android.systemui.statusbar.notification.NotificationEntryListener; @@ -191,7 +190,6 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { () -> mRowBinder, () -> mRemoteInputManager, mLeakDetector, - mock(ForegroundServiceDismissalFeatureController.class), mock(IStatusBarService.class), NotifLiveDataStoreMocksKt.createNotifLiveDataStoreImplMock(), mock(DumpManager.class) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index 7d8e0d26464c..e9d8f5830131 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -82,8 +82,8 @@ import com.android.systemui.statusbar.notification.collection.provider.HighPrior import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.wmshell.BubblesManager; @@ -124,7 +124,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Mock private NotificationInfo.CheckSaveListener mCheckSaveListener; @Mock private OnSettingsClickListener mOnSettingsClickListener; @Mock private DeviceProvisionedController mDeviceProvisionedController; - @Mock private StatusBar mStatusBar; + @Mock private CentralSurfaces mCentralSurfaces; @Mock private AccessibilityManager mAccessibilityManager; @Mock private HighPriorityProvider mHighPriorityProvider; @Mock private INotificationManager mINotificationManager; @@ -155,7 +155,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false); mGutsManager = new NotificationGutsManager(mContext, - () -> Optional.of(mStatusBar), mHandler, mHandler, mAccessibilityManager, + () -> Optional.of(mCentralSurfaces), mHandler, mHandler, mAccessibilityManager, mHighPriorityProvider, mINotificationManager, mNotificationEntryManager, mPeopleSpaceWidgetManager, mLauncherApps, mShortcutManager, mChannelEditorDialogController, mContextTracker, mAssistantFeedbackController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java index c4f954fee1f6..1561b5a5d22e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java @@ -58,7 +58,6 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; -import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotifCollection; @@ -68,14 +67,13 @@ import com.android.systemui.statusbar.notification.collection.legacy.VisualStabi import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController.NotificationPanelEvent; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.ZenModeController; @@ -118,7 +116,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { @Mock(answer = Answers.RETURNS_SELF) private NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder; @Mock private NotificationSwipeHelper mNotificationSwipeHelper; - @Mock private StatusBar mStatusBar; + @Mock private CentralSurfaces mCentralSurfaces; @Mock private ScrimController mScrimController; @Mock private NotificationGroupManagerLegacy mLegacyGroupManager; @Mock private SectionHeaderController mSilentHeaderController; @@ -129,9 +127,6 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { @Mock private IStatusBarService mIStatusBarService; @Mock private UiEventLogger mUiEventLogger; @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController; - @Mock private ForegroundServiceDismissalFeatureController mFgFeatureController; - @Mock private ForegroundServiceSectionController mFgServicesSectionController; - @Mock private ForegroundServiceDungeonView mForegroundServiceDungeonView; @Mock private LayoutInflater mLayoutInflater; @Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock private VisualStabilityManager mVisualStabilityManager; @@ -151,8 +146,6 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { when(mNotificationSwipeHelperBuilder.build()).thenReturn(mNotificationSwipeHelper); when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false); - when(mFgServicesSectionController.createView(mLayoutInflater)) - .thenReturn(mForegroundServiceDungeonView); mController = new NotificationStackScrollLayoutController( true, @@ -175,7 +168,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { new FalsingManagerFake(), mResources, mNotificationSwipeHelperBuilder, - mStatusBar, + mCentralSurfaces, mScrimController, mLegacyGroupManager, mLegacyGroupManager, @@ -187,8 +180,6 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { mLockscreenShadeTransitionController, mIStatusBarService, mUiEventLogger, - mFgFeatureController, - mFgServicesSectionController, mLayoutInflater, mRemoteInputManager, mVisualStabilityManager, @@ -399,22 +390,6 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { } @Test - public void testForegroundDismissEnabled() { - when(mFgFeatureController.isForegroundServiceDismissalEnabled()).thenReturn(true); - mController.attach(mNotificationStackScrollLayout); - verify(mNotificationStackScrollLayout).initializeForegroundServiceSection( - mForegroundServiceDungeonView); - } - - @Test - public void testForegroundDismissaDisabled() { - when(mFgFeatureController.isForegroundServiceDismissalEnabled()).thenReturn(false); - mController.attach(mNotificationStackScrollLayout); - verify(mNotificationStackScrollLayout, never()).initializeForegroundServiceSection( - any(ForegroundServiceDungeonView.class)); - } - - @Test public void testUpdateFooter_remoteInput() { ArgumentCaptor<RemoteInputController.Callback> callbackCaptor = ArgumentCaptor.forClass(RemoteInputController.Callback.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 4f731ed5f72c..eafcc354fac4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -61,9 +61,9 @@ import com.android.systemui.statusbar.notification.collection.render.GroupExpans import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.FooterView; +import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import org.junit.Assert; @@ -89,7 +89,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { private AmbientState mAmbientState; @Rule public MockitoRule mockito = MockitoJUnit.rule(); - @Mock private StatusBar mBar; + @Mock private CentralSurfaces mCentralSurfaces; @Mock private SysuiStatusBarStateController mBarState; @Mock private NotificationGroupManagerLegacy mGroupMembershipManger; @Mock private NotificationGroupManagerLegacy mGroupExpansionManager; @@ -141,7 +141,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper); mStackScroller = spy(mStackScrollerInternal); mStackScroller.setShelfController(notificationShelfController); - mStackScroller.setStatusBar(mBar); + mStackScroller.setCentralSurfaces(mCentralSurfaces); mStackScroller.setEmptyShadeView(mEmptyShadeView); when(mStackScrollLayoutController.isHistoryEnabled()).thenReturn(true); when(mStackScrollLayoutController.getNoticationRoundessManager()) @@ -149,7 +149,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mStackScroller.setController(mStackScrollLayoutController); // Stub out functionality that isn't necessary to test. - doNothing().when(mBar) + doNothing().when(mCentralSurfaces) .executeRunnableDismissingKeyguard(any(Runnable.class), any(Runnable.class), anyBoolean(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java index 25950f2e8caa..9bfb2c4ce00c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java @@ -57,8 +57,8 @@ import java.util.Optional; @SmallTest @RunWith(AndroidTestingRunner.class) -public class StatusBarCommandQueueCallbacksTest extends SysuiTestCase { - @Mock private StatusBar mStatusBar; +public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase { + @Mock private CentralSurfaces mCentralSurfaces; @Mock private ShadeController mShadeController; @Mock private CommandQueue mCommandQueue; @Mock private NotificationPanelViewController mNotificationPanelViewController; @@ -81,14 +81,14 @@ public class StatusBarCommandQueueCallbacksTest extends SysuiTestCase { @Mock private LightBarController mLightBarController; @Mock private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; - StatusBarCommandQueueCallbacks mSbcqCallbacks; + CentralSurfacesCommandQueueCallbacks mSbcqCallbacks; @Before public void setup() { MockitoAnnotations.initMocks(this); - mSbcqCallbacks = new StatusBarCommandQueueCallbacks( - mStatusBar, + mSbcqCallbacks = new CentralSurfacesCommandQueueCallbacks( + mCentralSurfaces, mContext, mContext.getResources(), mShadeController, @@ -122,13 +122,13 @@ public class StatusBarCommandQueueCallbacksTest extends SysuiTestCase { @Test public void testDisableNotificationShade() { - when(mStatusBar.getDisabled1()).thenReturn(StatusBarManager.DISABLE_NONE); - when(mStatusBar.getDisabled2()).thenReturn(StatusBarManager.DISABLE_NONE); + when(mCentralSurfaces.getDisabled1()).thenReturn(StatusBarManager.DISABLE_NONE); + when(mCentralSurfaces.getDisabled2()).thenReturn(StatusBarManager.DISABLE_NONE); when(mCommandQueue.panelsEnabled()).thenReturn(false); mSbcqCallbacks.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE, StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false); - verify(mStatusBar).updateQsExpansionEnabled(); + verify(mCentralSurfaces).updateQsExpansionEnabled(); verify(mShadeController).animateCollapsePanels(); // Trying to open it does nothing. @@ -140,12 +140,13 @@ public class StatusBarCommandQueueCallbacksTest extends SysuiTestCase { @Test public void testEnableNotificationShade() { - when(mStatusBar.getDisabled1()).thenReturn(StatusBarManager.DISABLE_NONE); - when(mStatusBar.getDisabled2()).thenReturn(StatusBarManager.DISABLE2_NOTIFICATION_SHADE); + when(mCentralSurfaces.getDisabled1()).thenReturn(StatusBarManager.DISABLE_NONE); + when(mCentralSurfaces.getDisabled2()) + .thenReturn(StatusBarManager.DISABLE2_NOTIFICATION_SHADE); when(mCommandQueue.panelsEnabled()).thenReturn(true); mSbcqCallbacks.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE, StatusBarManager.DISABLE2_NONE, false); - verify(mStatusBar).updateQsExpansionEnabled(); + verify(mCentralSurfaces).updateQsExpansionEnabled(); verify(mShadeController, never()).animateCollapsePanels(); // Can now be opened. @@ -158,13 +159,13 @@ public class StatusBarCommandQueueCallbacksTest extends SysuiTestCase { @Test public void testSuppressAmbientDisplay_suppress() { mSbcqCallbacks.suppressAmbientDisplay(true); - verify(mDozeServiceHost).setDozeSuppressed(true); + verify(mDozeServiceHost).setAlwaysOnSuppressed(true); } @Test public void testSuppressAmbientDisplay_unsuppress() { mSbcqCallbacks.suppressAmbientDisplay(false); - verify(mDozeServiceHost).setDozeSuppressed(false); + verify(mDozeServiceHost).setAlwaysOnSuppressed(false); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java index 09794397c31e..953a330d2e65 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java @@ -139,7 +139,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.BatteryController; @@ -177,12 +177,12 @@ import dagger.Lazy; @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper(setAsMainLooper = true) -public class StatusBarTest extends SysuiTestCase { +public class CentralSurfacesTest extends SysuiTestCase { private static final int FOLD_STATE_FOLDED = 0; private static final int FOLD_STATE_UNFOLDED = 1; - private StatusBar mStatusBar; + private CentralSurfaces mCentralSurfaces; private FakeMetricsLogger mMetricsLogger; private PowerManager mPowerManager; private TestableNotificationInterruptStateProviderImpl mNotificationInterruptStateProvider; @@ -252,14 +252,12 @@ public class StatusBarTest extends SysuiTestCase { @Mock private ViewMediatorCallback mKeyguardVieMediatorCallback; @Mock private VolumeComponent mVolumeComponent; @Mock private CommandQueue mCommandQueue; - @Mock private StatusBarComponent.Factory mStatusBarComponentFactory; - @Mock private StatusBarComponent mStatusBarComponent; + @Mock private CentralSurfacesComponent.Factory mStatusBarComponentFactory; + @Mock private CentralSurfacesComponent mCentralSurfacesComponent; @Mock private PluginManager mPluginManager; @Mock private ViewMediatorCallback mViewMediatorCallback; @Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager; @Mock private ScreenPinningRequest mScreenPinningRequest; - @Mock private StatusBarNotificationActivityStarter.Builder - mStatusBarNotificationActivityStarterBuilder; @Mock private PluginDependencyProvider mPluginDependencyProvider; @Mock private KeyguardDismissUtil mKeyguardDismissUtil; @Mock private ExtensionController mExtensionController; @@ -336,8 +334,6 @@ public class StatusBarTest extends SysuiTestCase { mContext.setTheme(R.style.Theme_SystemUI_LightWallpaper); when(mStackScrollerController.getView()).thenReturn(mStackScroller); - when(mStackScrollerController.getNotificationListContainer()).thenReturn( - mNotificationListContainer); when(mStackScroller.generateLayoutParams(any())).thenReturn(new LayoutParams(0, 0)); when(mNotificationPanelViewController.getView()).thenReturn(mNotificationPanelView); when(mNotificationPanelView.getLayoutParams()).thenReturn(new LayoutParams(0, 0)); @@ -368,8 +364,8 @@ public class StatusBarTest extends SysuiTestCase { when(mLockscreenWallpaperLazy.get()).thenReturn(mLockscreenWallpaper); when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController); - when(mStatusBarComponentFactory.create()).thenReturn(mStatusBarComponent); - when(mStatusBarComponent.getNotificationShadeWindowViewController()).thenReturn( + when(mStatusBarComponentFactory.create()).thenReturn(mCentralSurfacesComponent); + when(mCentralSurfacesComponent.getNotificationShadeWindowViewController()).thenReturn( mNotificationShadeWindowViewController); doAnswer(invocation -> { ((Runnable) invocation.getArgument(0)).run(); @@ -379,12 +375,12 @@ public class StatusBarTest extends SysuiTestCase { mShadeController = new ShadeControllerImpl(mCommandQueue, mStatusBarStateController, mNotificationShadeWindowController, mStatusBarKeyguardViewManager, mContext.getSystemService(WindowManager.class), - () -> Optional.of(mStatusBar), () -> mAssistManager); + () -> Optional.of(mCentralSurfaces), () -> mAssistManager); when(mOperatorNameViewControllerFactory.create(any())) .thenReturn(mOperatorNameViewController); - mStatusBar = new StatusBar( + mCentralSurfaces = new CentralSurfaces( mContext, mNotificationsController, mock(FragmentService.class), @@ -445,7 +441,6 @@ public class StatusBarTest extends SysuiTestCase { mCommandQueue, mStatusBarComponentFactory, mPluginManager, - mStatusBarNotificationActivityStarterBuilder, mShadeController, mStatusBarKeyguardViewManager, mViewMediatorCallback, @@ -480,8 +475,8 @@ public class StatusBarTest extends SysuiTestCase { mDeviceStateManager, mDreamOverlayStateController, mWiredChargingRippleController); - when(mKeyguardViewMediator.registerStatusBar( - any(StatusBar.class), + when(mKeyguardViewMediator.registerCentralSurfaces( + any(CentralSurfaces.class), any(NotificationPanelViewController.class), any(PanelExpansionStateManager.class), any(BiometricUnlockController.class), @@ -492,23 +487,23 @@ public class StatusBarTest extends SysuiTestCase { when(mKeyguardViewMediator.getViewMediatorCallback()).thenReturn( mKeyguardVieMediatorCallback); - // TODO: we should be able to call mStatusBar.start() and have all the below values + // TODO: we should be able to call mCentralSurfaces.start() and have all the below values // initialized automatically. - mStatusBar.mNotificationShadeWindowView = mNotificationShadeWindowView; - mStatusBar.mNotificationPanelViewController = mNotificationPanelViewController; - mStatusBar.mDozeScrimController = mDozeScrimController; - mStatusBar.mPresenter = mNotificationPresenter; - mStatusBar.mKeyguardIndicationController = mKeyguardIndicationController; - mStatusBar.mBarService = mBarService; - mStatusBar.mStackScroller = mStackScroller; - mStatusBar.startKeyguard(); + mCentralSurfaces.mNotificationShadeWindowView = mNotificationShadeWindowView; + mCentralSurfaces.mNotificationPanelViewController = mNotificationPanelViewController; + mCentralSurfaces.mDozeScrimController = mDozeScrimController; + mCentralSurfaces.mPresenter = mNotificationPresenter; + mCentralSurfaces.mKeyguardIndicationController = mKeyguardIndicationController; + mCentralSurfaces.mBarService = mBarService; + mCentralSurfaces.mStackScroller = mStackScroller; + mCentralSurfaces.startKeyguard(); mInitController.executePostInitTasks(); notificationLogger.setUpWithContainer(mNotificationListContainer); } @Test public void testSetBouncerShowing_noCrash() { - mStatusBar.setBouncerShowing(true); + mCentralSurfaces.setBouncerShowing(true); } @Test @@ -516,7 +511,7 @@ public class StatusBarTest extends SysuiTestCase { when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(true); - mStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false); + mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, false, false, false); } @Test @@ -524,7 +519,7 @@ public class StatusBarTest extends SysuiTestCase { when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true); when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); - mStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false); + mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, false, false, false); } @Test @@ -532,7 +527,7 @@ public class StatusBarTest extends SysuiTestCase { when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false); - mStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false); + mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, false, false, false); } @Test @@ -544,7 +539,7 @@ public class StatusBarTest extends SysuiTestCase { when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false); when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); when(mKeyguardStateController.isMethodSecure()).thenReturn(false); - mStatusBar.onKeyguardViewManagerStatesUpdated(); + mCentralSurfaces.onKeyguardViewManagerStatesUpdated(); MetricsAsserts.assertHasLog("missing hidden insecure lockscreen log", mMetricsLogger.getLogs(), @@ -563,7 +558,7 @@ public class StatusBarTest extends SysuiTestCase { when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); when(mKeyguardStateController.isMethodSecure()).thenReturn(true); - mStatusBar.onKeyguardViewManagerStatesUpdated(); + mCentralSurfaces.onKeyguardViewManagerStatesUpdated(); MetricsAsserts.assertHasLog("missing hidden secure lockscreen log", mMetricsLogger.getLogs(), @@ -582,7 +577,7 @@ public class StatusBarTest extends SysuiTestCase { when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); when(mKeyguardStateController.isMethodSecure()).thenReturn(false); - mStatusBar.onKeyguardViewManagerStatesUpdated(); + mCentralSurfaces.onKeyguardViewManagerStatesUpdated(); MetricsAsserts.assertHasLog("missing insecure lockscreen showing", mMetricsLogger.getLogs(), @@ -601,7 +596,7 @@ public class StatusBarTest extends SysuiTestCase { when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); when(mKeyguardStateController.isMethodSecure()).thenReturn(true); - mStatusBar.onKeyguardViewManagerStatesUpdated(); + mCentralSurfaces.onKeyguardViewManagerStatesUpdated(); MetricsAsserts.assertHasLog("missing secure lockscreen showing log", mMetricsLogger.getLogs(), @@ -620,7 +615,7 @@ public class StatusBarTest extends SysuiTestCase { when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true); when(mKeyguardStateController.isMethodSecure()).thenReturn(true); - mStatusBar.onKeyguardViewManagerStatesUpdated(); + mCentralSurfaces.onKeyguardViewManagerStatesUpdated(); MetricsAsserts.assertHasLog("missing bouncer log", mMetricsLogger.getLogs(), @@ -721,7 +716,7 @@ public class StatusBarTest extends SysuiTestCase { @Test public void testLogHidden() { try { - mStatusBar.handleVisibleToUserChanged(false); + mCentralSurfaces.handleVisibleToUserChanged(false); mUiBgExecutor.runAllReady(); verify(mBarService, times(1)).onPanelHidden(); verify(mBarService, never()).onPanelRevealed(anyBoolean(), anyInt()); @@ -736,10 +731,10 @@ public class StatusBarTest extends SysuiTestCase { when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true); when(mNotificationsController.getActiveNotificationsCount()).thenReturn(5); when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(true); - mStatusBar.setBarStateForTest(StatusBarState.SHADE); + mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE); try { - mStatusBar.handleVisibleToUserChanged(true); + mCentralSurfaces.handleVisibleToUserChanged(true); mUiBgExecutor.runAllReady(); verify(mBarService, never()).onPanelHidden(); verify(mBarService, times(1)).onPanelRevealed(false, 1); @@ -755,10 +750,10 @@ public class StatusBarTest extends SysuiTestCase { when(mNotificationsController.getActiveNotificationsCount()).thenReturn(5); when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false); - mStatusBar.setBarStateForTest(StatusBarState.SHADE); + mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE); try { - mStatusBar.handleVisibleToUserChanged(true); + mCentralSurfaces.handleVisibleToUserChanged(true); mUiBgExecutor.runAllReady(); verify(mBarService, never()).onPanelHidden(); verify(mBarService, times(1)).onPanelRevealed(true, 5); @@ -773,10 +768,10 @@ public class StatusBarTest extends SysuiTestCase { when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false); when(mNotificationsController.getActiveNotificationsCount()).thenReturn(5); when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false); - mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); + mCentralSurfaces.setBarStateForTest(StatusBarState.KEYGUARD); try { - mStatusBar.handleVisibleToUserChanged(true); + mCentralSurfaces.handleVisibleToUserChanged(true); mUiBgExecutor.runAllReady(); verify(mBarService, never()).onPanelHidden(); verify(mBarService, times(1)).onPanelRevealed(false, 5); @@ -788,18 +783,18 @@ public class StatusBarTest extends SysuiTestCase { @Test public void testDump_DoesNotCrash() { - mStatusBar.dump(null, new PrintWriter(new ByteArrayOutputStream()), null); + mCentralSurfaces.dump(null, new PrintWriter(new ByteArrayOutputStream()), null); } @Test public void testDumpBarTransitions_DoesNotCrash() { - StatusBar.dumpBarTransitions( + CentralSurfaces.dumpBarTransitions( new PrintWriter(new ByteArrayOutputStream()), "var", /* transitions= */ null); } @Test public void testFingerprintNotification_UpdatesScrims() { - mStatusBar.notifyBiometricAuthModeChanged(); + mCentralSurfaces.notifyBiometricAuthModeChanged(); verify(mScrimController).transitionTo(any(), any()); } @@ -808,81 +803,81 @@ public class StatusBarTest extends SysuiTestCase { // Simulate unlocking from AoD with fingerprint. when(mBiometricUnlockController.getMode()) .thenReturn(BiometricUnlockController.MODE_WAKE_AND_UNLOCK); - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); verify(mScrimController).transitionTo(eq(ScrimState.UNLOCKED), any()); } @Test public void testTransitionLaunch_goesToUnlocked() { - mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); - mStatusBar.showKeyguardImpl(); + mCentralSurfaces.setBarStateForTest(StatusBarState.KEYGUARD); + mCentralSurfaces.showKeyguardImpl(); // Starting a pulse should change the scrim controller to the pulsing state when(mNotificationPanelViewController.isLaunchTransitionRunning()).thenReturn(true); when(mNotificationPanelViewController.isLaunchingAffordanceWithPreview()).thenReturn(true); - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); verify(mScrimController).transitionTo(eq(ScrimState.UNLOCKED), any()); } @Test public void testSetExpansionAffectsAlpha_whenKeyguardShowingButGoingAwayForAnyReason() { - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); verify(mScrimController).setExpansionAffectsAlpha(eq(true)); clearInvocations(mScrimController); when(mKeyguardStateController.isShowing()).thenReturn(true); when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(false); - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); verify(mScrimController).setExpansionAffectsAlpha(eq(true)); clearInvocations(mScrimController); when(mKeyguardStateController.isShowing()).thenReturn(true); when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true); - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); verify(mScrimController).setExpansionAffectsAlpha(eq(false)); clearInvocations(mScrimController); when(mKeyguardStateController.isShowing()).thenReturn(true); when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true); - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); verify(mScrimController).setExpansionAffectsAlpha(eq(false)); } @Test public void testTransitionLaunch_noPreview_doesntGoUnlocked() { - mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); - mStatusBar.showKeyguardImpl(); + mCentralSurfaces.setBarStateForTest(StatusBarState.KEYGUARD); + mCentralSurfaces.showKeyguardImpl(); // Starting a pulse should change the scrim controller to the pulsing state when(mNotificationPanelViewController.isLaunchTransitionRunning()).thenReturn(true); when(mNotificationPanelViewController.isLaunchingAffordanceWithPreview()).thenReturn(false); - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); verify(mScrimController).transitionTo(eq(ScrimState.KEYGUARD)); } @Test public void testSetOccluded_propagatesToScrimController() { - mStatusBar.setOccluded(true); + mCentralSurfaces.setOccluded(true); verify(mScrimController).setKeyguardOccluded(eq(true)); reset(mScrimController); - mStatusBar.setOccluded(false); + mCentralSurfaces.setOccluded(false); verify(mScrimController).setKeyguardOccluded(eq(false)); } @Test public void testPulseWhileDozing_updatesScrimController() { - mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); - mStatusBar.showKeyguardImpl(); + mCentralSurfaces.setBarStateForTest(StatusBarState.KEYGUARD); + mCentralSurfaces.showKeyguardImpl(); // Starting a pulse should change the scrim controller to the pulsing state when(mDozeServiceHost.isPulsing()).thenReturn(true); - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); verify(mScrimController).transitionTo(eq(ScrimState.PULSING), any()); // Ending a pulse should take it back to keyguard state when(mDozeServiceHost.isPulsing()).thenReturn(false); - mStatusBar.updateScrimController(); + mCentralSurfaces.updateScrimController(); verify(mScrimController).transitionTo(eq(ScrimState.KEYGUARD)); } @@ -890,45 +885,45 @@ public class StatusBarTest extends SysuiTestCase { public void testShowKeyguardImplementation_setsState() { when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>()); - mStatusBar.setBarStateForTest(StatusBarState.SHADE); + mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE); // By default, showKeyguardImpl sets state to KEYGUARD. - mStatusBar.showKeyguardImpl(); + mCentralSurfaces.showKeyguardImpl(); verify(mStatusBarStateController).setState( eq(StatusBarState.KEYGUARD), eq(false) /* force */); } @Test public void testOnStartedWakingUp_isNotDozing() { - mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); + mCentralSurfaces.setBarStateForTest(StatusBarState.KEYGUARD); when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true); when(mDozeServiceHost.getDozingRequested()).thenReturn(true); - mStatusBar.updateIsKeyguard(); + mCentralSurfaces.updateIsKeyguard(); // TODO: mNotificationPanelView.expand(false) gets called twice. Should be once. verify(mNotificationPanelViewController, times(2)).expand(eq(false)); clearInvocations(mNotificationPanelViewController); - mStatusBar.mWakefulnessObserver.onStartedWakingUp(); + mCentralSurfaces.mWakefulnessObserver.onStartedWakingUp(); verify(mDozeServiceHost).stopDozing(); verify(mNotificationPanelViewController).expand(eq(false)); } @Test public void testOnStartedWakingUp_doesNotDismissBouncer_whenPulsing() { - mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); + mCentralSurfaces.setBarStateForTest(StatusBarState.KEYGUARD); when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true); when(mDozeServiceHost.getDozingRequested()).thenReturn(true); - mStatusBar.updateIsKeyguard(); + mCentralSurfaces.updateIsKeyguard(); clearInvocations(mNotificationPanelViewController); - mStatusBar.setBouncerShowing(true); - mStatusBar.mWakefulnessObserver.onStartedWakingUp(); + mCentralSurfaces.setBouncerShowing(true); + mCentralSurfaces.mWakefulnessObserver.onStartedWakingUp(); verify(mNotificationPanelViewController, never()).expand(anyBoolean()); } @Test public void testRegisterBroadcastsonDispatcher() { - mStatusBar.registerBroadcastReceiver(); + mCentralSurfaces.registerBroadcastReceiver(); verify(mBroadcastDispatcher).registerReceiver( any(BroadcastReceiver.class), any(IntentFilter.class), @@ -938,7 +933,7 @@ public class StatusBarTest extends SysuiTestCase { @Test public void testUpdateResources_updatesBouncer() { - mStatusBar.updateResources(); + mCentralSurfaces.updateResources(); verify(mStatusBarKeyguardViewManager).updateResources(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java index 5f2bbd341962..077b41a0aa90 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java @@ -126,6 +126,12 @@ public class DozeParametersTest extends SysuiTestCase { setAodEnabledForTest(true); setShouldControlUnlockedScreenOffForTest(true); setDisplayNeedsBlankingForTest(false); + + // Default to false here (with one test to make sure that when it returns true, we respect + // that). We'll test the specific conditions for this to return true/false in the + // UnlockedScreenOffAnimationController's tests. + when(mUnlockedScreenOffAnimationController.shouldPlayUnlockedScreenOffAnimation()) + .thenReturn(false); } @Test @@ -174,9 +180,12 @@ public class DozeParametersTest extends SysuiTestCase { */ @Test public void testControlUnlockedScreenOffAnimation_dozeAfterScreenOff_false() { + mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(true); + // If AOD is disabled, we shouldn't want to control screen off. Also, let's double check // that when that value is updated, we called through to PowerManager. setAodEnabledForTest(false); + assertFalse(mDozeParameters.shouldControlScreenOff()); assertTrue(mPowerManagerDozeAfterScreenOff); @@ -188,7 +197,6 @@ public class DozeParametersTest extends SysuiTestCase { @Test public void testControlUnlockedScreenOffAnimationDisabled_dozeAfterScreenOff() { - setShouldControlUnlockedScreenOffForTest(true); when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(false); assertFalse(mDozeParameters.shouldControlUnlockedScreenOff()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java index 6ce3b4b7b6f9..26ac70c70e7f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java @@ -82,7 +82,7 @@ public class DozeServiceHostTest extends SysuiTestCase { @Mock private NotificationShadeWindowController mNotificationShadeWindowController; @Mock private PowerManager mPowerManager; @Mock private WakefulnessLifecycle mWakefullnessLifecycle; - @Mock private StatusBar mStatusBar; + @Mock private CentralSurfaces mCentralSurfaces; @Mock private NotificationIconAreaController mNotificationIconAreaController; @Mock private NotificationShadeWindowViewController mNotificationShadeWindowViewController; @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @@ -103,7 +103,7 @@ public class DozeServiceHostTest extends SysuiTestCase { mAuthController, mNotificationIconAreaController); mDozeServiceHost.initialize( - mStatusBar, + mCentralSurfaces, mStatusBarKeyguardViewManager, mNotificationShadeWindowViewController, mNotificationPanel, @@ -119,7 +119,7 @@ public class DozeServiceHostTest extends SysuiTestCase { mDozeServiceHost.startDozing(); verify(mStatusBarStateController).setIsDozing(eq(true)); - verify(mStatusBar).updateIsKeyguard(); + verify(mCentralSurfaces).updateIsKeyguard(); mDozeServiceHost.stopDozing(); verify(mStatusBarStateController).setIsDozing(eq(false)); @@ -128,8 +128,8 @@ public class DozeServiceHostTest extends SysuiTestCase { @Test public void testPulseWhileDozing_updatesScrimController() { - mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); - mStatusBar.showKeyguardImpl(); + mCentralSurfaces.setBarStateForTest(StatusBarState.KEYGUARD); + mCentralSurfaces.showKeyguardImpl(); // Keep track of callback to be able to stop the pulse // DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1]; @@ -154,12 +154,12 @@ public class DozeServiceHostTest extends SysuiTestCase { verify(mDozeScrimController).pulse( pulseCallbackArgumentCaptor.capture(), eq(DozeLog.PULSE_REASON_NOTIFICATION)); - verify(mStatusBar).updateScrimController(); - reset(mStatusBar); + verify(mCentralSurfaces).updateScrimController(); + reset(mCentralSurfaces); pulseCallbackArgumentCaptor.getValue().onPulseFinished(); assertFalse(mDozeScrimController.isPulsing()); - verify(mStatusBar).updateScrimController(); + verify(mCentralSurfaces).updateScrimController(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java index 421d8f6a1889..db5741c90ebc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java @@ -63,7 +63,6 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { @Mock private NotificationGroupManagerLegacy mGroupManager; @Mock private View mNotificationShadeWindowView; @Mock private VisualStabilityProvider mVSProvider; - @Mock private StatusBar mBar; @Mock private StatusBarStateController mStatusBarStateController; @Mock private KeyguardBypassController mBypassController; @Mock private ConfigurationControllerImpl mConfigurationController; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt index 3257a84f14d6..31465f45af42 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt @@ -25,7 +25,7 @@ import java.util.concurrent.Executor class KeyguardBottomAreaTest : SysuiTestCase() { @Mock - private lateinit var mStatusBar: StatusBar + private lateinit var mCentralSurfaces: CentralSurfaces private lateinit var mKeyguardBottomArea: KeyguardBottomAreaView @Before @@ -42,7 +42,7 @@ class KeyguardBottomAreaTest : SysuiTestCase() { mKeyguardBottomArea = LayoutInflater.from(mContext).inflate( R.layout.keyguard_bottom_area, null, false) as KeyguardBottomAreaView - mKeyguardBottomArea.setStatusBar(mStatusBar) + mKeyguardBottomArea.setCentralSurfaces(mCentralSurfaces) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java index 479c27192c55..1af7035a441b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java @@ -130,6 +130,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.stack.AmbientState; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; @@ -168,7 +169,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { private static final int NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE = 50; @Mock - private StatusBar mStatusBar; + private CentralSurfaces mCentralSurfaces; @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout; @Mock @@ -358,6 +359,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { private NotificationShadeWindowController mNotificationShadeWindowController; @Mock private SysUiState mSysUiState; + @Mock + private NotificationListContainer mNotificationListContainer; private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty(); private SysuiStatusBarStateController mStatusBarStateController; private NotificationPanelViewController mNotificationPanelViewController; @@ -387,8 +390,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { when(mResources.getBoolean(R.bool.config_enableNotificationShadeDrag)).thenReturn(true); when(mResources.getDimensionPixelSize(R.dimen.notifications_top_padding_split_shade)) .thenReturn(NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE); - when(mResources.getDimensionPixelSize(R.dimen.qs_panel_width)).thenReturn(400); - when(mResources.getDimensionPixelSize(R.dimen.notification_panel_width)).thenReturn(400); + when(mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_horizontal)) + .thenReturn(10); when(mView.getContext()).thenReturn(getContext()); when(mView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar); when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(mUserSwitcherView); @@ -542,9 +545,10 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { mInteractionJankMonitor, mQsFrameTranslateController, mSysUiState, - mKeyguardUnlockAnimationController); + mKeyguardUnlockAnimationController, + mNotificationListContainer); mNotificationPanelViewController.initDependencies( - mStatusBar, + mCentralSurfaces, () -> {}, mNotificationShelfController); mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager); @@ -786,25 +790,31 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { } @Test - public void testSinglePaneShadeLayout_childrenHaveConstantWidth() { - enableSplitShade(/* enabled= */ false); + public void testSplitShadeLayout_childrenHaveInsideMarginsOfZero() { + enableSplitShade(/* enabled= */ true); mNotificationPanelViewController.updateResources(); - assertThat(getConstraintSetLayout(R.id.qs_frame).mWidth) - .isEqualTo(mResources.getDimensionPixelSize(R.dimen.qs_panel_width)); - assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).mWidth) - .isEqualTo(mResources.getDimensionPixelSize(R.dimen.notification_panel_width)); + assertThat(getConstraintSetLayout(R.id.qs_frame).startMargin).isEqualTo(10); + assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin).isEqualTo(0); + assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startMargin) + .isEqualTo(0); + assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).endMargin) + .isEqualTo(10); } @Test - public void testSplitShadeLayout_childrenHaveZeroWidth() { - enableSplitShade(/* enabled= */ true); + public void testSinglePaneLayout_childrenHaveEqualMargins() { + enableSplitShade(/* enabled= */ false); mNotificationPanelViewController.updateResources(); - assertThat(getConstraintSetLayout(R.id.qs_frame).mWidth).isEqualTo(0); - assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).mWidth).isEqualTo(0); + assertThat(getConstraintSetLayout(R.id.qs_frame).startMargin).isEqualTo(10); + assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin).isEqualTo(10); + assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startMargin) + .isEqualTo(10); + assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).endMargin) + .isEqualTo(10); } @Test @@ -904,6 +914,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { public void testSwitchesToCorrectClockInSplitShade() { mStatusBarStateController.setState(KEYGUARD); enableSplitShade(/* enabled= */ true); + clearInvocations(mKeyguardStatusViewController); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); triggerPositionClockAndNotifications(); @@ -918,11 +929,56 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { } @Test + public void testHasNotifications_switchesToLargeClockWhenEnteringSplitShade() { + mStatusBarStateController.setState(KEYGUARD); + when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1); + + enableSplitShade(/* enabled= */ true); + + verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true); + } + + @Test + public void testNoNotifications_switchesToLargeClockWhenEnteringSplitShade() { + mStatusBarStateController.setState(KEYGUARD); + when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); + + enableSplitShade(/* enabled= */ true); + + verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true); + } + + @Test + public void testHasNotifications_switchesToSmallClockWhenExitingSplitShade() { + mStatusBarStateController.setState(KEYGUARD); + enableSplitShade(/* enabled= */ true); + clearInvocations(mKeyguardStatusViewController); + when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1); + + enableSplitShade(/* enabled= */ false); + + verify(mKeyguardStatusViewController).displayClock(SMALL, /* animate */ true); + } + + @Test + public void testNoNotifications_switchesToLargeClockWhenExitingSplitShade() { + mStatusBarStateController.setState(KEYGUARD); + enableSplitShade(/* enabled= */ true); + clearInvocations(mKeyguardStatusViewController); + when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); + + enableSplitShade(/* enabled= */ false); + + verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true); + } + + @Test public void testSwitchesToBigClockInSplitShadeOnAod() { mStatusBarStateController.setState(KEYGUARD); enableSplitShade(/* enabled= */ true); when(mMediaDataManager.hasActiveMedia()).thenReturn(true); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + clearInvocations(mKeyguardStatusViewController); mNotificationPanelViewController.setDozing(true, false, null); @@ -934,6 +990,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(false); mStatusBarStateController.setState(KEYGUARD); enableSplitShade(/* enabled= */ true); + clearInvocations(mKeyguardStatusViewController); when(mMediaDataManager.hasActiveMedia()).thenReturn(true); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); @@ -946,6 +1003,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { public void testDisplaysSmallClockOnLockscreenInSplitShadeWhenMediaIsPlaying() { mStatusBarStateController.setState(KEYGUARD); enableSplitShade(/* enabled= */ true); + clearInvocations(mKeyguardStatusViewController); when(mMediaDataManager.hasActiveMedia()).thenReturn(true); // one notification + media player visible diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt index 34a5d4b03dbb..093f92646115 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt @@ -61,7 +61,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { @Mock private lateinit var mStatusBarStateController: SysuiStatusBarStateController @Mock - private lateinit var mStatusBar: StatusBar + private lateinit var mCentralSurfaces: CentralSurfaces @Mock private lateinit var mDockManager: DockManager @Mock @@ -107,10 +107,11 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { mStatusBarKeyguardViewManager, mStatusBarWindowStateController, mLockIconViewController, - Optional.of(mLowLightClockController) + Optional.of(mLowLightClockController), + mCentralSurfaces, + mNotificationShadeWindowController ) mController.setupExpandedStatusBar() - mController.setService(mStatusBar, mNotificationShadeWindowController) mInteractionEventHandlerCaptor = ArgumentCaptor.forClass(InteractionEventHandler::class.java) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java index 6c33113ae58b..62a1bcdc0184 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java @@ -71,7 +71,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { @Mock private DragDownHelper mDragDownHelper; @Mock private SysuiStatusBarStateController mStatusBarStateController; @Mock private ShadeController mShadeController; - @Mock private StatusBar mStatusBar; + @Mock private CentralSurfaces mCentralSurfaces; @Mock private DockManager mDockManager; @Mock private NotificationPanelViewController mNotificationPanelViewController; @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout; @@ -115,9 +115,10 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { mStatusBarKeyguardViewManager, mStatusBarWindowStateController, mLockIconViewController, - Optional.of(mLowLightClockController)); + Optional.of(mLowLightClockController), + mCentralSurfaces, + mNotificationShadeWindowController); mController.setupExpandedStatusBar(); - mController.setService(mStatusBar, mNotificationShadeWindowController); mController.setDragDownHelper(mDragDownHelper); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt index 589116184710..9ab88dc2d764 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.unfold.SysUIUnfoldComponent import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider +import com.android.systemui.util.view.ViewUtil import com.android.systemui.util.mockito.any import com.google.common.truth.Truth.assertThat import org.junit.Before @@ -63,6 +64,8 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { private lateinit var configurationController: ConfigurationController @Mock private lateinit var userSwitcherController: StatusBarUserSwitcherController + @Mock + private lateinit var viewUtil: ViewUtil private lateinit var view: PhoneStatusBarView private lateinit var controller: PhoneStatusBarViewController @@ -80,7 +83,6 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { val parent = FrameLayout(mContext) // add parent to keep layout params view = LayoutInflater.from(mContext) .inflate(R.layout.status_bar, parent, false) as PhoneStatusBarView - view.setLeftTopRightBottom(VIEW_LEFT, VIEW_TOP, VIEW_RIGHT, VIEW_BOTTOM) } controller = createAndInitController(view) @@ -111,64 +113,6 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { verify(moveFromCenterAnimation).onViewsReady(any()) } - @Test - fun touchIsWithinView_inBounds_returnsTrue() { - val view = createViewMockWithScreenLocation() - controller = createAndInitController(view) - - assertThat(controller.touchIsWithinView(VIEW_LEFT + 1f, VIEW_TOP + 1f)).isTrue() - } - - @Test - fun touchIsWithinView_onTopLeftCorner_returnsTrue() { - val view = createViewMockWithScreenLocation() - controller = createAndInitController(view) - - assertThat(controller.touchIsWithinView(VIEW_LEFT.toFloat(), VIEW_TOP.toFloat())).isTrue() - } - - @Test - fun touchIsWithinView_onBottomRightCorner_returnsTrue() { - val view = createViewMockWithScreenLocation() - controller = createAndInitController(view) - - assertThat(controller.touchIsWithinView( - VIEW_RIGHT.toFloat(), VIEW_BOTTOM.toFloat()) - ).isTrue() - } - - @Test - fun touchIsWithinView_xTooSmall_returnsFalse() { - val view = createViewMockWithScreenLocation() - controller = createAndInitController(view) - - assertThat(controller.touchIsWithinView(VIEW_LEFT - 1f, VIEW_TOP + 1f)).isFalse() - } - - @Test - fun touchIsWithinView_xTooLarge_returnsFalse() { - val view = createViewMockWithScreenLocation() - controller = createAndInitController(view) - - assertThat(controller.touchIsWithinView(VIEW_RIGHT + 1f, VIEW_TOP + 1f)).isFalse() - } - - @Test - fun touchIsWithinView_yTooSmall_returnsFalse() { - val view = createViewMockWithScreenLocation() - controller = createAndInitController(view) - - assertThat(controller.touchIsWithinView(VIEW_LEFT + 1f, VIEW_TOP - 1f)).isFalse() - } - - @Test - fun touchIsWithinView_yTooLarge_returnsFalse() { - val view = createViewMockWithScreenLocation() - controller = createAndInitController(view) - - assertThat(controller.touchIsWithinView(VIEW_LEFT + 1f, VIEW_BOTTOM + 1f)).isFalse() - } - private fun createViewMock(): PhoneStatusBarView { val view = spy(view) val viewTreeObserver = mock(ViewTreeObserver::class.java) @@ -177,20 +121,12 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { return view } - private fun createViewMockWithScreenLocation(): PhoneStatusBarView { - val view = spy(view) - val location = IntArray(2) - location[0] = VIEW_LEFT - location[1] = VIEW_TOP - `when`(view.locationOnScreen).thenReturn(location) - return view - } - private fun createAndInitController(view: PhoneStatusBarView): PhoneStatusBarViewController { return PhoneStatusBarViewController.Factory( Optional.of(sysuiUnfoldComponent), Optional.of(progressProvider), userSwitcherController, + viewUtil, configurationController ).create(view, touchEventHandler).also { it.init() @@ -215,8 +151,3 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { } } } - -private const val VIEW_LEFT = 30 -private const val VIEW_RIGHT = 100 -private const val VIEW_TOP = 40 -private const val VIEW_BOTTOM = 100 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 8b93de571cc9..f4f55ccefd09 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 @@ -75,7 +75,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Mock private KeyguardStateController mKeyguardStateController; @Mock - private StatusBar mStatusBar; + private CentralSurfaces mCentralSurfaces; @Mock private ViewGroup mContainer; @Mock @@ -118,7 +118,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { any(ViewGroup.class), any(KeyguardBouncer.BouncerExpansionCallback.class))) .thenReturn(mBouncer); - when(mStatusBar.getBouncerContainer()).thenReturn(mContainer); + when(mCentralSurfaces.getBouncerContainer()).thenReturn(mContainer); when(mContainer.findViewById(anyInt())).thenReturn(mKeyguardMessageArea); mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager( getContext(), @@ -138,8 +138,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { Optional.of(mSysUiUnfoldComponent), () -> mShadeController, mLatencyTracker); - mStatusBarKeyguardViewManager.registerStatusBar( - mStatusBar, + mStatusBarKeyguardViewManager.registerCentralSurfaces( + mCentralSurfaces, mNotificationPanelView, new PanelExpansionStateManager(), mBiometricUnlockController, @@ -261,7 +261,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Test public void onPanelExpansionChanged_neverTranslatesBouncerWhenLaunchingApp() { - when(mStatusBar.isInLaunchTransition()).thenReturn(true); + when(mCentralSurfaces.isInLaunchTransition()).thenReturn(true); mStatusBarKeyguardViewManager.onPanelExpansionChanged( /* fraction= */ KeyguardBouncer.EXPANSION_VISIBLE, /* expanded= */ true, @@ -272,12 +272,12 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Test public void setOccluded_animatesPanelExpansion_onlyIfBouncerHidden() { mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, true /* animated */); - verify(mStatusBar).animateKeyguardUnoccluding(); + verify(mCentralSurfaces).animateKeyguardUnoccluding(); when(mBouncer.isShowing()).thenReturn(true); - clearInvocations(mStatusBar); + clearInvocations(mCentralSurfaces); mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, true /* animated */); - verify(mStatusBar, never()).animateKeyguardUnoccluding(); + verify(mCentralSurfaces, never()).animateKeyguardUnoccluding(); } @Test @@ -303,7 +303,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Test public void setOccluded_isInLaunchTransition_onKeyguardOccludedChangedCalled() { - when(mStatusBar.isInLaunchTransition()).thenReturn(true); + when(mCentralSurfaces.isInLaunchTransition()).thenReturn(true); mStatusBarKeyguardViewManager.show(null); mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */); @@ -312,7 +312,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Test public void setOccluded_isLaunchingActivityOverLockscreen_onKeyguardOccludedChangedCalled() { - when(mStatusBar.isLaunchingActivityOverLockscreen()).thenReturn(true); + when(mCentralSurfaces.isLaunchingActivityOverLockscreen()).thenReturn(true); mStatusBarKeyguardViewManager.show(null); mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 743311f99ca2..ace7415f2c17 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -113,7 +113,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { @Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock - private StatusBar mStatusBar; + private CentralSurfaces mCentralSurfaces; @Mock private KeyguardStateController mKeyguardStateController; @Mock @@ -203,7 +203,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mJankMonitor); mNotificationActivityStarter = - new StatusBarNotificationActivityStarter.Builder( + new StatusBarNotificationActivityStarter( getContext(), mock(CommandQueue.class), mHandler, @@ -229,18 +229,16 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mock(LockPatternUtils.class), mock(StatusBarRemoteInputCallback.class), mActivityIntentHelper, - mNotifPipelineFlags, mock(MetricsLogger.class), mock(StatusBarNotificationActivityStarterLogger.class), - mOnUserInteractionCallback) - .setStatusBar(mStatusBar) - .setNotificationPresenter(mock(NotificationPresenter.class)) - .setNotificationPanelViewController( - mock(NotificationPanelViewController.class)) - .setActivityLaunchAnimator(mActivityLaunchAnimator) - .setNotificationAnimatorControllerProvider(notificationAnimationProvider) - .build(); + mOnUserInteractionCallback, + mCentralSurfaces, + mock(NotificationPresenter.class), + mock(NotificationPanelViewController.class), + mActivityLaunchAnimator, + notificationAnimationProvider + ); // set up dismissKeyguardThenExecute to synchronously invoke the OnDismissAction arg doAnswer(mCallOnDismiss).when(mActivityStarter).dismissKeyguardThenExecute( @@ -269,7 +267,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { sbn.getNotification().flags |= Notification.FLAG_AUTO_CANCEL; when(mKeyguardStateController.isShowing()).thenReturn(true); - when(mStatusBar.isOccluded()).thenReturn(true); + when(mCentralSurfaces.isOccluded()).thenReturn(true); // When mNotificationActivityStarter.onNotificationClicked(sbn, mNotificationRow); @@ -328,7 +326,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { // Given sbn.getNotification().contentIntent = null; when(mKeyguardStateController.isShowing()).thenReturn(true); - when(mStatusBar.isOccluded()).thenReturn(true); + when(mCentralSurfaces.isOccluded()).thenReturn(true); // When mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow); @@ -358,7 +356,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { // Given sbn.getNotification().contentIntent = mContentIntent; when(mKeyguardStateController.isShowing()).thenReturn(true); - when(mStatusBar.isOccluded()).thenReturn(true); + when(mCentralSurfaces.isOccluded()).thenReturn(true); // When mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow); @@ -402,6 +400,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mNotificationActivityStarter.handleFullScreenIntent(entry); // THEN display should try wake up for the full screen intent - verify(mStatusBar).wakeUpForFullScreenIntent(); + verify(mCentralSurfaces).wakeUpForFullScreenIntent(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index 7d9e6b4c1620..1a3dd3a7a2a5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -37,6 +37,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.ForegroundServiceNotificationListener; import com.android.systemui.InitController; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardIndicationController; @@ -79,7 +80,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { private CommandQueue mCommandQueue; private FakeMetricsLogger mMetricsLogger; private ShadeController mShadeController = mock(ShadeController.class); - private StatusBar mStatusBar = mock(StatusBar.class); + private CentralSurfaces mCentralSurfaces = mock(CentralSurfaces.class); private InitController mInitController = new InitController(); @Before @@ -101,19 +102,24 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { mock(NotificationStackScrollLayoutController.class); when(stackScrollLayoutController.getView()).thenReturn( mock(NotificationStackScrollLayout.class)); - when(stackScrollLayoutController.getNotificationListContainer()).thenReturn( - mock(NotificationListContainer.class)); when(notificationShadeWindowView.getResources()).thenReturn(mContext.getResources()); - mStatusBarNotificationPresenter = new StatusBarNotificationPresenter(mContext, - mock(NotificationPanelViewController.class), mock(HeadsUpManagerPhone.class), - notificationShadeWindowView, stackScrollLayoutController, - mock(DozeScrimController.class), mock(ScrimController.class), - mock(NotificationShadeWindowController.class), mock(DynamicPrivacyController.class), + mStatusBarNotificationPresenter = new StatusBarNotificationPresenter( + mContext, + mock(NotificationPanelViewController.class), + mock(HeadsUpManagerPhone.class), + notificationShadeWindowView, + mock(ActivityStarter.class), + stackScrollLayoutController, + mock(DozeScrimController.class), + mock(ScrimController.class), + mock(NotificationShadeWindowController.class), + mock(DynamicPrivacyController.class), mock(KeyguardStateController.class), mock(KeyguardIndicationController.class), - mStatusBar, - mock(ShadeControllerImpl.class), mock(LockscreenShadeTransitionController.class), + mCentralSurfaces, + mock(ShadeControllerImpl.class), + mock(LockscreenShadeTransitionController.class), mCommandQueue, mock(NotificationViewHierarchyManager.class), mock(NotificationLockscreenUserManager.class), @@ -128,7 +134,9 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { mNotificationInterruptStateProvider, mock(NotificationRemoteInputManager.class), mock(ConfigurationController.class), - mock(NotifPipelineFlags.class)); + mock(NotifPipelineFlags.class), + mock(NotificationRemoteInputManager.Callback.class), + mock(NotificationListContainer.class)); mInitController.executePostInitTasks(); ArgumentCaptor<NotificationInterruptSuppressor> suppressorCaptor = ArgumentCaptor.forClass(NotificationInterruptSuppressor.class); @@ -195,9 +203,9 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { .setTag("a") .setNotification(n) .build(); - when(mStatusBar.areNotificationAlertsDisabled()).thenReturn(true); + when(mCentralSurfaces.areNotificationAlertsDisabled()).thenReturn(true); - assertTrue("StatusBar alerts disabled shouldn't allow interruptions", + assertTrue("CentralSurfaces alerts disabled shouldn't allow interruptions", mInterruptSuppressor.suppressInterruptions(entry)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt index 71b32c0bd106..0936b773d4b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.StatusBarStateControllerImpl import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.settings.GlobalSettings +import junit.framework.Assert.assertFalse import org.junit.After import org.junit.Before import org.junit.Test @@ -61,7 +62,7 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { @Mock private lateinit var globalSettings: GlobalSettings @Mock - private lateinit var statusBar: StatusBar + private lateinit var mCentralSurfaces: CentralSurfaces @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController @Mock @@ -93,8 +94,8 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { powerManager, handler = handler ) - controller.initialize(statusBar, lightRevealScrim) - `when`(statusBar.notificationPanelViewController).thenReturn( + controller.initialize(mCentralSurfaces, lightRevealScrim) + `when`(mCentralSurfaces.notificationPanelViewController).thenReturn( notificationPanelViewController) // Screen off does not run if the panel is expanded, so we should say it's collapsed to test @@ -133,7 +134,7 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { */ @Test fun testAodUiShownIfNotInteractive() { - `when`(dozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true) + `when`(dozeParameters.canControlUnlockedScreenOff()).thenReturn(true) `when`(powerManager.isInteractive).thenReturn(false) val callbackCaptor = ArgumentCaptor.forClass(Runnable::class.java) @@ -156,7 +157,7 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { */ @Test fun testAodUiNotShownIfInteractive() { - `when`(dozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true) + `when`(dozeParameters.canControlUnlockedScreenOff()).thenReturn(true) `when`(powerManager.isInteractive).thenReturn(true) val callbackCaptor = ArgumentCaptor.forClass(Runnable::class.java) @@ -167,4 +168,13 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { verify(notificationPanelViewController, never()).showAodUi() } + + @Test + fun testNoAnimationPlaying_dozeParamsCanNotControlScreenOff() { + `when`(dozeParameters.canControlUnlockedScreenOff()).thenReturn(false) + + assertFalse(controller.shouldPlayUnlockedScreenOffAnimation()) + controller.startAnimation() + assertFalse(controller.isAnimationPlaying()) + } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java index 586161716829..509509401d13 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java @@ -17,6 +17,8 @@ package com.android.systemui.statusbar.phone.fragment; import static android.view.Display.DEFAULT_DISPLAY; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeast; @@ -27,6 +29,7 @@ import android.app.Fragment; import android.app.StatusBarManager; import android.content.Context; import android.os.Bundle; +import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.view.View; @@ -56,6 +59,9 @@ import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentCom import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.settings.SecureSettings; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -82,6 +88,8 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { private final CommandQueue mCommandQueue = mock(CommandQueue.class); private OperatorNameViewController.Factory mOperatorNameViewControllerFactory; private OperatorNameViewController mOperatorNameViewController; + private SecureSettings mSecureSettings; + private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); @Mock private StatusBarFragmentComponent.Factory mStatusBarFragmentComponentFactory; @@ -298,6 +306,40 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { assertEquals(mStatusBarFragmentComponent, fragment.getStatusBarFragmentComponent()); } + @Test + public void testBlockedIcons_obeysSettingForVibrateIcon_settingOff() { + CollapsedStatusBarFragment fragment = resumeAndGetFragment(); + String str = mContext.getString(com.android.internal.R.string.status_bar_volume); + + // GIVEN the setting is off + when(mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0)) + .thenReturn(0); + + // WHEN CollapsedStatusBarFragment builds the blocklist + fragment.updateBlockedIcons(); + + // THEN status_bar_volume SHOULD be present in the list + boolean contains = fragment.getBlockedIcons().contains(str); + assertTrue(contains); + } + + @Test + public void testBlockedIcons_obeysSettingForVibrateIcon_settingOn() { + CollapsedStatusBarFragment fragment = resumeAndGetFragment(); + String str = mContext.getString(com.android.internal.R.string.status_bar_volume); + + // GIVEN the setting is ON + when(mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0)) + .thenReturn(1); + + // WHEN CollapsedStatusBarFragment builds the blocklist + fragment.updateBlockedIcons(); + + // THEN status_bar_volume SHOULD NOT be present in the list + boolean contains = fragment.getBlockedIcons().contains(str); + assertFalse(contains); + } + @Override protected Fragment instantiate(Context context, String className, Bundle arguments) { MockitoAnnotations.initMocks(this); @@ -313,6 +355,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { mOperatorNameViewControllerFactory = mock(OperatorNameViewController.Factory.class); when(mOperatorNameViewControllerFactory.create(any())) .thenReturn(mOperatorNameViewController); + mSecureSettings = mock(SecureSettings.class); setUpNotificationIconAreaController(); return new CollapsedStatusBarFragment( @@ -334,7 +377,9 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { new LogBuffer("TEST", 1, 1, mock(LogcatEchoTracker.class)), new DisableFlagsLogger() ), - mOperatorNameViewControllerFactory); + mOperatorNameViewControllerFactory, + mSecureSettings, + mExecutor); } private void setUpDaggerComponent() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt index 807664d093da..1c48eca797a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt @@ -105,6 +105,7 @@ class OngoingCallControllerTest : SysuiTestCase() { val notificationCollection = mock(CommonNotifCollection::class.java) controller = OngoingCallController( + context, notificationCollection, mockOngoingCallFlags, clock, @@ -204,17 +205,15 @@ class OngoingCallControllerTest : SysuiTestCase() { /** Regression test for b/194731244. */ @Test - fun onEntryUpdated_calledManyTimes_uidObserverUnregisteredManyTimes() { - val numCalls = 4 - - for (i in 0 until numCalls) { + fun onEntryUpdated_calledManyTimes_uidObserverOnlyRegisteredOnce() { + for (i in 0 until 4) { // Re-create the notification each time so that it's considered a different object and - // observers will get re-registered (and hopefully unregistered). + // will re-trigger the whole flow. notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry()) } - // There should be 1 observer still registered, so we should unregister n-1 times. - verify(mockIActivityManager, times(numCalls - 1)).unregisterUidObserver(any()) + verify(mockIActivityManager, times(1)) + .registerUidObserver(any(), any(), any(), any()) } /** Regression test for b/216248574. */ @@ -238,6 +237,18 @@ class OngoingCallControllerTest : SysuiTestCase() { notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry()) } + /** Regression test for b/216248574. */ + @Test + fun entryUpdated_packageNameProvidedToActivityManager() { + notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry()) + + val packageNameCaptor = ArgumentCaptor.forClass(String::class.java) + verify(mockIActivityManager).registerUidObserver( + any(), any(), any(), packageNameCaptor.capture() + ) + assertThat(packageNameCaptor.value).isNotNull() + } + /** * If a call notification is never added before #onEntryRemoved is called, then the listener * should never be notified. diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt new file mode 100644 index 000000000000..3a5d9ee16b0a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt @@ -0,0 +1,31 @@ +package com.android.systemui.statusbar.policy + +import android.content.res.Configuration + +/** Fake implementation of [ConfigurationController] for tests. */ +class FakeConfigurationController : ConfigurationController { + + private var listener: ConfigurationController.ConfigurationListener? = null + + override fun addCallback(listener: ConfigurationController.ConfigurationListener) { + this.listener = listener + } + + override fun removeCallback(listener: ConfigurationController.ConfigurationListener) { + this.listener = null + } + + override fun onConfigurationChanged(newConfiguration: Configuration?) { + listener?.onConfigChanged(newConfiguration) + } + + override fun notifyThemeChanged() { + listener?.onThemeChanged() + } + + fun notifyConfigurationChanged() { + onConfigurationChanged(newConfiguration = null) + } + + override fun isLayoutRtl(): Boolean = false +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt new file mode 100644 index 000000000000..dead1592992d --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt @@ -0,0 +1,72 @@ +package com.android.systemui.util.view + +import android.view.View +import android.widget.TextView +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.spy +import org.mockito.Mockito.`when` + +@SmallTest +class ViewUtilTest : SysuiTestCase() { + private val viewUtil = ViewUtil() + private lateinit var view: View + + @Before + fun setUp() { + view = TextView(context) + view.setLeftTopRightBottom(VIEW_LEFT, VIEW_TOP, VIEW_RIGHT, VIEW_BOTTOM) + + view = spy(view) + val location = IntArray(2) + location[0] = VIEW_LEFT + location[1] = VIEW_TOP + `when`(view.locationOnScreen).thenReturn(location) + } + + @Test + fun touchIsWithinView_inBounds_returnsTrue() { + assertThat(viewUtil.touchIsWithinView(view, VIEW_LEFT + 1f, VIEW_TOP + 1f)).isTrue() + } + + @Test + fun touchIsWithinView_onTopLeftCorner_returnsTrue() { + assertThat(viewUtil.touchIsWithinView( + view, VIEW_LEFT.toFloat(), VIEW_TOP.toFloat()) + ).isTrue() + } + + @Test + fun touchIsWithinView_onBottomRightCorner_returnsTrue() { + assertThat(viewUtil.touchIsWithinView(view, VIEW_RIGHT.toFloat(), VIEW_BOTTOM.toFloat())) + .isTrue() + } + + @Test + fun touchIsWithinView_xTooSmall_returnsFalse() { + assertThat(viewUtil.touchIsWithinView(view, VIEW_LEFT - 1f, VIEW_TOP + 1f)).isFalse() + } + + @Test + fun touchIsWithinView_xTooLarge_returnsFalse() { + assertThat(viewUtil.touchIsWithinView(view, VIEW_RIGHT + 1f, VIEW_TOP + 1f)).isFalse() + } + + @Test + fun touchIsWithinView_yTooSmall_returnsFalse() { + assertThat(viewUtil.touchIsWithinView(view, VIEW_LEFT + 1f, VIEW_TOP - 1f)).isFalse() + } + + @Test + fun touchIsWithinView_yTooLarge_returnsFalse() { + assertThat(viewUtil.touchIsWithinView(view, VIEW_LEFT + 1f, VIEW_BOTTOM + 1f)).isFalse() + } +} + +private const val VIEW_LEFT = 30 +private const val VIEW_RIGHT = 100 +private const val VIEW_TOP = 40 +private const val VIEW_BOTTOM = 100 diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java index 8ad6271bfc7e..2be67edfc946 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java @@ -43,6 +43,10 @@ public class FakeStatusBarIconController extends BaseLeakChecker<IconManager> } @Override + public void refreshIconGroup(IconManager iconManager) { + } + + @Override public void setExternalIcon(String slot) { } diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index 593b97e55739..82880febc7f0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -1221,7 +1221,7 @@ public class BubblesTest extends SysuiTestCase { final Context userContext = setUpContextWithPackageManager(workPkg, mock(ApplicationInfo.class)); - // If things are working correctly, StatusBar.getPackageManagerForUser will call this + // If things are working correctly, CentralSurfaces.getPackageManagerForUser will call this when(context.createPackageContextAsUser(eq(workPkg), anyInt(), eq(workUser))) .thenReturn(userContext); diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java index 2b7b97737e0f..bf8b18ce3157 100644 --- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java +++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java @@ -50,6 +50,7 @@ import android.os.Handler; import android.os.Parcel; import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.UserHandle; import android.util.PackageUtils; import android.util.Slog; @@ -201,8 +202,10 @@ class AssociationRequestsProcessor { // requests at the same time. // If the application already has a pending association request, that PendingIntent // will be cancelled. - pendingIntent = PendingIntent.getActivity(mContext, /*requestCode */ packageUid, intent, - FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE); + pendingIntent = PendingIntent.getActivityAsUser( + mContext, /*requestCode */ packageUid, intent, + FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE, + /* options= */ null, UserHandle.CURRENT); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java b/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java index 2c42c910b9ab..adc8459de658 100644 --- a/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java +++ b/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java @@ -33,17 +33,19 @@ import com.android.internal.annotations.GuardedBy; /** * Handles blocking access to the camera for apps running on virtual devices. */ -class CameraAccessController extends CameraManager.AvailabilityCallback { +class CameraAccessController extends CameraManager.AvailabilityCallback implements AutoCloseable { private static final String TAG = "CameraAccessController"; private final Object mLock = new Object(); private final Context mContext; - private VirtualDeviceManagerInternal mVirtualDeviceManagerInternal; - CameraAccessBlockedCallback mBlockedCallback; - private CameraManager mCameraManager; - private boolean mListeningForCameraEvents; - private PackageManager mPackageManager; + private final VirtualDeviceManagerInternal mVirtualDeviceManagerInternal; + private final CameraAccessBlockedCallback mBlockedCallback; + private final CameraManager mCameraManager; + private final PackageManager mPackageManager; + + @GuardedBy("mLock") + private int mObserverCount = 0; @GuardedBy("mLock") private ArrayMap<String, InjectionSessionData> mPackageToSessionData = new ArrayMap<>(); @@ -77,21 +79,36 @@ class CameraAccessController extends CameraManager.AvailabilityCallback { */ public void startObservingIfNeeded() { synchronized (mLock) { - if (!mListeningForCameraEvents) { + if (mObserverCount == 0) { mCameraManager.registerAvailabilityCallback(mContext.getMainExecutor(), this); - mListeningForCameraEvents = true; } + mObserverCount++; } } /** * Stop watching for camera access. */ - public void stopObserving() { + public void stopObservingIfNeeded() { + synchronized (mLock) { + mObserverCount--; + if (mObserverCount <= 0) { + close(); + } + } + } + + + @Override + public void close() { synchronized (mLock) { - mCameraManager.unregisterAvailabilityCallback(this); - mListeningForCameraEvents = false; + if (mObserverCount < 0) { + Slog.wtf(TAG, "Unexpected negative mObserverCount: " + mObserverCount); + } else if (mObserverCount > 0) { + Slog.w(TAG, "Unexpected close with observers remaining: " + mObserverCount); + } } + mCameraManager.unregisterAvailabilityCallback(this); } @Override diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java index bc1f28d1c373..b991ba87eef4 100644 --- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java @@ -24,6 +24,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.compat.CompatChanges; import android.companion.virtual.VirtualDeviceManager.ActivityListener; +import android.companion.virtual.VirtualDeviceParams; +import android.companion.virtual.VirtualDeviceParams.ActivityPolicy; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.ComponentName; @@ -77,7 +79,9 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @Nullable private final ArraySet<ComponentName> mBlockedActivities; private final Object mGenericWindowPolicyControllerLock = new Object(); - private Consumer<ActivityInfo> mActivityBlockedCallback; + @ActivityPolicy + private final int mDefaultActivityPolicy; + private final Consumer<ActivityInfo> mActivityBlockedCallback; @NonNull @GuardedBy("mGenericWindowPolicyControllerLock") @@ -95,18 +99,30 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController * @param windowFlags The window flags that this controller is interested in. * @param systemWindowFlags The system window flags that this controller is interested in. * @param allowedUsers The set of users that are allowed to stream in this display. + * @param allowedActivities The set of activities explicitly allowed to stream on this device. + * Used only if the {@code activityPolicy} is + * {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_BLOCKED}. + * @param blockedActivities The set of activities explicitly blocked from streaming on this + * device. Used only if the {@code activityPolicy} is + * {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_ALLOWED} + * @param defaultActivityPolicy Whether activities are default allowed to be displayed or + * blocked. * @param activityListener Activity listener to listen for activity changes. The display ID * is not populated in this callback and is always {@link Display#INVALID_DISPLAY}. + * @param activityBlockedCallback Callback that is called when an activity is blocked from + * launching. */ public GenericWindowPolicyController(int windowFlags, int systemWindowFlags, @NonNull ArraySet<UserHandle> allowedUsers, - @Nullable Set<ComponentName> allowedActivities, - @Nullable Set<ComponentName> blockedActivities, + @NonNull Set<ComponentName> allowedActivities, + @NonNull Set<ComponentName> blockedActivities, + @ActivityPolicy int defaultActivityPolicy, @NonNull ActivityListener activityListener, @NonNull Consumer<ActivityInfo> activityBlockedCallback) { mAllowedUsers = allowedUsers; - mAllowedActivities = allowedActivities == null ? null : new ArraySet<>(allowedActivities); - mBlockedActivities = blockedActivities == null ? null : new ArraySet<>(blockedActivities); + mAllowedActivities = new ArraySet<>(allowedActivities); + mBlockedActivities = new ArraySet<>(blockedActivities); + mDefaultActivityPolicy = defaultActivityPolicy; mActivityBlockedCallback = activityBlockedCallback; setInterestedWindowFlags(windowFlags, systemWindowFlags); mActivityListener = activityListener; @@ -191,11 +207,13 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController Slog.d(TAG, "Virtual device activity not allowed from user " + activityUser); return false; } - if (mBlockedActivities != null && mBlockedActivities.contains(activityComponent)) { + if (mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED + && mBlockedActivities.contains(activityComponent)) { Slog.d(TAG, "Virtual device blocking launch of " + activityComponent); return false; } - if (mAllowedActivities != null && !mAllowedActivities.contains(activityComponent)) { + if (mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_BLOCKED + && !mAllowedActivities.contains(activityComponent)) { Slog.d(TAG, activityComponent + " is not in the allowed list."); return false; } diff --git a/services/companion/java/com/android/server/companion/virtual/PermissionUtils.java b/services/companion/java/com/android/server/companion/virtual/PermissionUtils.java index c397ea2997a4..77b880f6e62f 100644 --- a/services/companion/java/com/android/server/companion/virtual/PermissionUtils.java +++ b/services/companion/java/com/android/server/companion/virtual/PermissionUtils.java @@ -18,6 +18,8 @@ package com.android.server.companion.virtual; import android.content.Context; import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.UserHandle; import android.util.Slog; /** @@ -32,13 +34,15 @@ class PermissionUtils { * * @param context the context * @param callingPackage the calling application package name - * @param callingUid the calling application uid - * @return {@code true} if the package name matches the calling app uid, {@code false} otherwise + * @return {@code true} if the package name matches {@link Binder#getCallingUid()}, or + * {@code false} otherwise */ - public static boolean validatePackageName(Context context, String callingPackage, - int callingUid) { + public static boolean validateCallingPackageName(Context context, String callingPackage) { + final int callingUid = Binder.getCallingUid(); + final long token = Binder.clearCallingIdentity(); try { - int packageUid = context.getPackageManager().getPackageUid(callingPackage, 0); + int packageUid = context.getPackageManager() + .getPackageUidAsUser(callingPackage, UserHandle.getUserId(callingUid)); if (packageUid != callingUid) { Slog.e(LOG_TAG, "validatePackageName: App with package name " + callingPackage + " is UID " + packageUid + " but caller is " + callingUid); @@ -48,6 +52,8 @@ class PermissionUtils { Slog.e(LOG_TAG, "validatePackageName: App with package name " + callingPackage + " does not exist"); return false; + } finally { + Binder.restoreCallingIdentity(token); } return true; } 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 c0a904fe3d9a..b05a7dbe83d1 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -140,7 +140,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub int ownerUid, InputController inputController, OnDeviceCloseListener listener, PendingTrampolineCallback pendingTrampolineCallback, IVirtualDeviceActivityListener activityListener, VirtualDeviceParams params) { - mContext = context; + UserHandle ownerUserHandle = UserHandle.getUserHandleForUid(ownerUid); + mContext = context.createContextAsUser(ownerUserHandle, 0); mAssociationInfo = associationInfo; mPendingTrampolineCallback = pendingTrampolineCallback; mActivityListener = activityListener; @@ -505,6 +506,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub getAllowedUserHandles(), mParams.getAllowedActivities(), mParams.getBlockedActivities(), + mParams.getDefaultActivityPolicy(), createListenerAdapter(displayId), activityInfo -> onActivityBlocked(displayId, activityInfo)); mWindowPolicyControllers.put(displayId, dwpc); diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java index c7d8daac606b..9f252d744144 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java @@ -36,6 +36,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Parcel; import android.os.RemoteException; +import android.os.UserHandle; import android.util.ExceptionUtils; import android.util.Slog; import android.util.SparseArray; @@ -66,7 +67,12 @@ public class VirtualDeviceManagerService extends SystemService { private VirtualDeviceManagerInternal mLocalService; private final Handler mHandler = new Handler(Looper.getMainLooper()); private final PendingTrampolineMap mPendingTrampolines = new PendingTrampolineMap(mHandler); - private final CameraAccessController mCameraAccessController; + /** + * Mapping from user IDs to CameraAccessControllers. + */ + @GuardedBy("mVirtualDeviceManagerLock") + private final SparseArray<CameraAccessController> mCameraAccessControllers = + new SparseArray<>(); /** * Mapping from CDM association IDs to virtual devices. Only one virtual device is allowed for @@ -94,8 +100,6 @@ public class VirtualDeviceManagerService extends SystemService { super(context); mImpl = new VirtualDeviceManagerImpl(); mLocalService = new LocalService(); - mCameraAccessController = new CameraAccessController(getContext(), mLocalService, - this::onCameraAccessBlocked); } private final ActivityInterceptorCallback mActivityInterceptorCallback = @@ -144,16 +148,19 @@ public class VirtualDeviceManagerService extends SystemService { @Override public void onUserStarting(@NonNull TargetUser user) { super.onUserStarting(user); + Context userContext = getContext().createContextAsUser(user.getUserHandle(), 0); synchronized (mVirtualDeviceManagerLock) { - final CompanionDeviceManager cdm = getContext() - .createContextAsUser(user.getUserHandle(), 0) - .getSystemService(CompanionDeviceManager.class); + final CompanionDeviceManager cdm = + userContext.getSystemService(CompanionDeviceManager.class); final int userId = user.getUserIdentifier(); mAllAssociations.put(userId, cdm.getAllAssociations()); OnAssociationsChangedListener listener = associations -> mAllAssociations.put(userId, associations); mOnAssociationsChangedListeners.put(userId, listener); cdm.addOnAssociationsChangedListener(Runnable::run, listener); + CameraAccessController cameraAccessController = new CameraAccessController( + userContext, mLocalService, this::onCameraAccessBlocked); + mCameraAccessControllers.put(user.getUserIdentifier(), cameraAccessController); } } @@ -171,6 +178,14 @@ public class VirtualDeviceManagerService extends SystemService { cdm.removeOnAssociationsChangedListener(listener); mOnAssociationsChangedListeners.remove(userId); } + CameraAccessController cameraAccessController = mCameraAccessControllers.get( + user.getUserIdentifier()); + if (cameraAccessController != null) { + cameraAccessController.close(); + mCameraAccessControllers.remove(user.getUserIdentifier()); + } else { + Slog.w(TAG, "Cannot unregister cameraAccessController for user " + user); + } } } @@ -198,7 +213,7 @@ public class VirtualDeviceManagerService extends SystemService { android.Manifest.permission.CREATE_VIRTUAL_DEVICE, "createVirtualDevice"); final int callingUid = getCallingUid(); - if (!PermissionUtils.validatePackageName(getContext(), packageName, callingUid)) { + if (!PermissionUtils.validateCallingPackageName(getContext(), packageName)) { throw new SecurityException( "Package name " + packageName + " does not belong to calling uid " + callingUid); @@ -213,6 +228,9 @@ public class VirtualDeviceManagerService extends SystemService { "Virtual device for association ID " + associationId + " already exists"); } + final int userId = UserHandle.getUserId(callingUid); + final CameraAccessController cameraAccessController = + mCameraAccessControllers.get(userId); VirtualDeviceImpl virtualDevice = new VirtualDeviceImpl(getContext(), associationInfo, token, callingUid, new VirtualDeviceImpl.OnDeviceCloseListener() { @@ -220,14 +238,21 @@ public class VirtualDeviceManagerService extends SystemService { public void onClose(int associationId) { synchronized (mVirtualDeviceManagerLock) { mVirtualDevices.remove(associationId); - if (mVirtualDevices.size() == 0) { - mCameraAccessController.stopObserving(); + if (cameraAccessController != null) { + cameraAccessController.stopObservingIfNeeded(); + } else { + Slog.w(TAG, "cameraAccessController not found for user " + + userId); } } } }, this, activityListener, params); - mCameraAccessController.startObservingIfNeeded(); + if (cameraAccessController != null) { + cameraAccessController.startObservingIfNeeded(); + } else { + Slog.w(TAG, "cameraAccessController not found for user " + userId); + } mVirtualDevices.put(associationInfo.getId(), virtualDevice); return virtualDevice; } diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java index ff2308c35b9f..a0f239d43927 100644 --- a/services/core/java/com/android/server/NetworkTimeUpdateService.java +++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java @@ -16,6 +16,7 @@ package com.android.server; +import android.annotation.NonNull; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.timedetector.NetworkTimeSuggestion; @@ -38,6 +39,7 @@ import android.os.PowerManager; import android.os.SystemClock; import android.os.TimestampedValue; import android.provider.Settings; +import android.util.LocalLog; import android.util.Log; import android.util.NtpTrustedTime; import android.util.TimeUtils; @@ -95,6 +97,13 @@ public class NetworkTimeUpdateService extends Binder { // connection to happen. private int mTryAgainCounter; + /** + * A log that records the decisions to fetch a network time update. + * This is logged in bug reports to assist with debugging issues with network time suggestions. + */ + @NonNull + private final LocalLog mLocalLog = new LocalLog(30, false /* useLocalTimestamps */); + public NetworkTimeUpdateService(Context context) { mContext = context; mTime = NtpTrustedTime.getInstance(context); @@ -155,15 +164,29 @@ public class NetworkTimeUpdateService extends Binder { } private void onPollNetworkTimeUnderWakeLock(int event) { + long currentElapsedRealtimeMillis = SystemClock.elapsedRealtime(); // Force an NTP fix when outdated NtpTrustedTime.TimeResult cachedNtpResult = mTime.getCachedTimeResult(); - if (cachedNtpResult == null || cachedNtpResult.getAgeMillis() >= mPollingIntervalMs) { + if (cachedNtpResult == null || cachedNtpResult.getAgeMillis(currentElapsedRealtimeMillis) + >= mPollingIntervalMs) { if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh"); - mTime.forceRefresh(); + boolean isSuccessful = mTime.forceRefresh(); + if (!isSuccessful) { + String logMsg = "forceRefresh() returned false: cachedNtpResult=" + cachedNtpResult + + ", currentElapsedRealtimeMillis=" + currentElapsedRealtimeMillis; + + if (DBG) { + Log.d(TAG, logMsg); + } + mLocalLog.log(logMsg); + } + cachedNtpResult = mTime.getCachedTimeResult(); } - if (cachedNtpResult != null && cachedNtpResult.getAgeMillis() < mPollingIntervalMs) { + if (cachedNtpResult != null + && cachedNtpResult.getAgeMillis(currentElapsedRealtimeMillis) + < mPollingIntervalMs) { // Obtained fresh fix; schedule next normal update resetAlarm(mPollingIntervalMs); @@ -180,6 +203,11 @@ public class NetworkTimeUpdateService extends Binder { resetAlarm(mPollingIntervalShorterMs); } else { // Try much later + String logMsg = "mTryAgainTimesMax exceeded, cachedNtpResult=" + cachedNtpResult; + if (DBG) { + Log.d(TAG, logMsg); + } + mLocalLog.log(logMsg); mTryAgainCounter = 0; resetAlarm(mPollingIntervalMs); } @@ -285,6 +313,8 @@ public class NetworkTimeUpdateService extends Binder { if (ntpResult != null) { pw.println("NTP result age: " + ntpResult.getAgeMillis()); } + pw.println("Local logs:"); + mLocalLog.dump(fd, pw, args); pw.println(); } } diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java index 4d5384c17f1f..d07590fc8db5 100644 --- a/services/core/java/com/android/server/am/AppRestrictionController.java +++ b/services/core/java/com/android/server/am/AppRestrictionController.java @@ -191,7 +191,7 @@ public final class AppRestrictionController { // No lock is needed, as it's immutable after initialization in constructor. private final ArrayList<BaseAppStateTracker> mAppStateTrackers = new ArrayList<>(); - @GuardedBy("mLock") + @GuardedBy("mSettingsLock") private final RestrictionSettings mRestrictionSettings = new RestrictionSettings(); private final CopyOnWriteArraySet<AppBackgroundRestrictionListener> mRestrictionListeners = @@ -201,7 +201,7 @@ public final class AppRestrictionController { * A mapping between the UID/Pkg and its pending work which should be triggered on inactive; * an active UID/pkg pair should have an entry here, although its pending work could be null. */ - @GuardedBy("mLock") + @GuardedBy("mSettingsLock") private final SparseArrayMap<String, Runnable> mActiveUids = new SparseArrayMap<>(); // No lock is needed as it's accessed in bg handler thread only. @@ -218,6 +218,7 @@ public final class AppRestrictionController { private int[] mDeviceIdleExceptIdleAllowlist = new int[0]; // No lock is needed. private final Object mLock = new Object(); + private final Object mSettingsLock = new Object(); private final Injector mInjector; private final NotificationHelper mNotificationHelper; @@ -344,7 +345,7 @@ public final class AppRestrictionController { * {@link android.app.ActivityManager.RESTRICTION_LEVEL_*}. */ final class RestrictionSettings { - @GuardedBy("mLock") + @GuardedBy("mSettingsLock") final SparseArrayMap<String, PkgSettings> mRestrictionLevels = new SparseArrayMap(); final class PkgSettings { @@ -365,6 +366,7 @@ public final class AppRestrictionController { mCurrentRestrictionLevel = mLastRestrictionLevel = RESTRICTION_LEVEL_UNKNOWN; } + @GuardedBy("mSettingsLock") @RestrictionLevel int update(@RestrictionLevel int level, int reason, int subReason) { if (level != mCurrentRestrictionLevel) { mLastRestrictionLevel = mCurrentRestrictionLevel; @@ -378,6 +380,7 @@ public final class AppRestrictionController { } @Override + @GuardedBy("mSettingsLock") public String toString() { final StringBuilder sb = new StringBuilder(128); sb.append("RestrictionLevel{"); @@ -396,21 +399,23 @@ public final class AppRestrictionController { } void dump(PrintWriter pw, @ElapsedRealtimeLong long nowElapsed) { - pw.print(toString()); - if (mLastRestrictionLevel != RESTRICTION_LEVEL_UNKNOWN) { - pw.print('/'); - pw.print(ActivityManager.restrictionLevelToName(mLastRestrictionLevel)); - } - pw.print(" levelChange="); - TimeUtils.formatDuration(mLevelChangeTimeElapsed - nowElapsed, pw); - if (mLastNotificationShownTimeElapsed != null) { - for (int i = 0; i < mLastNotificationShownTimeElapsed.length; i++) { - if (mLastNotificationShownTimeElapsed[i] > 0) { - pw.print(" lastNoti("); - pw.print(mNotificationHelper.notificationTypeToString(i)); - pw.print(")="); - TimeUtils.formatDuration( - mLastNotificationShownTimeElapsed[i] - nowElapsed, pw); + synchronized (mSettingsLock) { + pw.print(toString()); + if (mLastRestrictionLevel != RESTRICTION_LEVEL_UNKNOWN) { + pw.print('/'); + pw.print(ActivityManager.restrictionLevelToName(mLastRestrictionLevel)); + } + pw.print(" levelChange="); + TimeUtils.formatDuration(mLevelChangeTimeElapsed - nowElapsed, pw); + if (mLastNotificationShownTimeElapsed != null) { + for (int i = 0; i < mLastNotificationShownTimeElapsed.length; i++) { + if (mLastNotificationShownTimeElapsed[i] > 0) { + pw.print(" lastNoti("); + pw.print(mNotificationHelper.notificationTypeToString(i)); + pw.print(")="); + TimeUtils.formatDuration( + mLastNotificationShownTimeElapsed[i] - nowElapsed, pw); + } } } } @@ -426,18 +431,22 @@ public final class AppRestrictionController { return mUid; } + @GuardedBy("mSettingsLock") @RestrictionLevel int getCurrentRestrictionLevel() { return mCurrentRestrictionLevel; } + @GuardedBy("mSettingsLock") @RestrictionLevel int getLastRestrictionLevel() { return mLastRestrictionLevel; } + @GuardedBy("mSettingsLock") int getReason() { return mReason; } + @GuardedBy("mSettingsLock") @ElapsedRealtimeLong long getLastNotificationTime( @NotificationHelper.NotificationType int notificationType) { if (mLastNotificationShownTimeElapsed == null) { @@ -446,6 +455,7 @@ public final class AppRestrictionController { return mLastNotificationShownTimeElapsed[notificationType]; } + @GuardedBy("mSettingsLock") void setLastNotificationTime(@NotificationHelper.NotificationType int notificationType, @ElapsedRealtimeLong long timestamp) { if (mLastNotificationShownTimeElapsed == null) { @@ -455,6 +465,7 @@ public final class AppRestrictionController { mLastNotificationShownTimeElapsed[notificationType] = timestamp; } + @GuardedBy("mSettingsLock") int getNotificationId(@NotificationHelper.NotificationType int notificationType) { if (mNotificationId == null) { return 0; @@ -462,6 +473,7 @@ public final class AppRestrictionController { return mNotificationId[notificationType]; } + @GuardedBy("mSettingsLock") void setNotificationId(@NotificationHelper.NotificationType int notificationType, int notificationId) { if (mNotificationId == null) { @@ -478,7 +490,7 @@ public final class AppRestrictionController { */ @RestrictionLevel int update(String packageName, int uid, @RestrictionLevel int level, int reason, int subReason) { - synchronized (mLock) { + synchronized (mSettingsLock) { PkgSettings settings = getRestrictionSettingsLocked(uid, packageName); if (settings == null) { settings = new PkgSettings(packageName, uid); @@ -492,7 +504,7 @@ public final class AppRestrictionController { * @return The reason of why it's in this level. */ int getReason(String packageName, int uid) { - synchronized (mLock) { + synchronized (mSettingsLock) { final PkgSettings settings = mRestrictionLevels.get(uid, packageName); return settings != null ? settings.getReason() : (REASON_MAIN_DEFAULT | REASON_SUB_DEFAULT_UNDEFINED); @@ -500,7 +512,7 @@ public final class AppRestrictionController { } @RestrictionLevel int getRestrictionLevel(int uid) { - synchronized (mLock) { + synchronized (mSettingsLock) { final int uidKeyIndex = mRestrictionLevels.indexOfKey(uid); if (uidKeyIndex < 0) { return RESTRICTION_LEVEL_UNKNOWN; @@ -522,7 +534,7 @@ public final class AppRestrictionController { } @RestrictionLevel int getRestrictionLevel(int uid, String packageName) { - synchronized (mLock) { + synchronized (mSettingsLock) { final PkgSettings settings = getRestrictionSettingsLocked(uid, packageName); return settings == null ? getRestrictionLevel(uid) : settings.getCurrentRestrictionLevel(); @@ -536,14 +548,14 @@ public final class AppRestrictionController { } private @RestrictionLevel int getLastRestrictionLevel(int uid, String packageName) { - synchronized (mLock) { + synchronized (mSettingsLock) { final PkgSettings settings = mRestrictionLevels.get(uid, packageName); return settings == null - ? RESTRICTION_LEVEL_UNKNOWN : settings.mLastRestrictionLevel; + ? RESTRICTION_LEVEL_UNKNOWN : settings.getLastRestrictionLevel(); } } - @GuardedBy("mLock") + @GuardedBy("mSettingsLock") void forEachPackageInUidLocked(int uid, @NonNull TriConsumer<String, Integer, Integer> consumer) { final int uidKeyIndex = mRestrictionLevels.indexOfKey(uid); @@ -558,20 +570,20 @@ public final class AppRestrictionController { } } - @GuardedBy("mLock") + @GuardedBy("mSettingsLock") void forEachUidLocked(@NonNull Consumer<Integer> consumer) { for (int i = mRestrictionLevels.numMaps() - 1; i >= 0; i--) { consumer.accept(mRestrictionLevels.keyAt(i)); } } - @GuardedBy("mLock") + @GuardedBy("mSettingsLock") PkgSettings getRestrictionSettingsLocked(int uid, String packageName) { return mRestrictionLevels.get(uid, packageName); } void removeUser(@UserIdInt int userId) { - synchronized (mLock) { + synchronized (mSettingsLock) { for (int i = mRestrictionLevels.numMaps() - 1; i >= 0; i--) { final int uid = mRestrictionLevels.keyAt(i); if (UserHandle.getUserId(uid) != userId) { @@ -583,28 +595,29 @@ public final class AppRestrictionController { } void removePackage(String pkgName, int uid) { - synchronized (mLock) { + synchronized (mSettingsLock) { mRestrictionLevels.delete(uid, pkgName); } } void removeUid(int uid) { - synchronized (mLock) { + synchronized (mSettingsLock) { mRestrictionLevels.delete(uid); } } @VisibleForTesting void reset() { - synchronized (mLock) { + synchronized (mSettingsLock) { mRestrictionLevels.clear(); } } - @GuardedBy("mLock") - void dumpLocked(PrintWriter pw, String prefix) { + void dump(PrintWriter pw, String prefix) { final ArrayList<PkgSettings> settings = new ArrayList<>(); - mRestrictionLevels.forEach(setting -> settings.add(setting)); + synchronized (mSettingsLock) { + mRestrictionLevels.forEach(setting -> settings.add(setting)); + } Collections.sort(settings, Comparator.comparingInt(PkgSettings::getUid)); final long nowElapsed = SystemClock.elapsedRealtime(); for (int i = 0, size = settings.size(); i < size; i++) { @@ -908,7 +921,9 @@ public final class AppRestrictionController { @VisibleForTesting void resetRestrictionSettings() { - mRestrictionSettings.reset(); + synchronized (mSettingsLock) { + mRestrictionSettings.reset(); + } initRestrictionStates(); } @@ -1309,9 +1324,7 @@ public final class AppRestrictionController { prefix = " " + prefix; pw.print(prefix); pw.println("BACKGROUND RESTRICTION LEVEL SETTINGS"); - synchronized (mLock) { - mRestrictionSettings.dumpLocked(pw, " " + prefix); - } + mRestrictionSettings.dump(pw, " " + prefix); mConstantsObserver.dump(pw, " " + prefix); for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) { pw.println(); @@ -1323,7 +1336,7 @@ public final class AppRestrictionController { int curBucket, boolean allowUpdateBucket, int reason, int subReason) { int curLevel; int prevReason; - synchronized (mLock) { + synchronized (mSettingsLock) { curLevel = getRestrictionLevel(uid, pkgName); if (curLevel == level) { // Nothing to do. @@ -1361,7 +1374,7 @@ public final class AppRestrictionController { || level == RESTRICTION_LEVEL_RESTRICTED_BUCKET)) { // restrict the app if it hasn't done so. boolean doIt = true; - synchronized (mLock) { + synchronized (mSettingsLock) { final int index = mActiveUids.indexOfKey(uid, pkgName); if (index >= 0) { // It's currently active, enqueue it. @@ -1379,7 +1392,7 @@ public final class AppRestrictionController { && level < RESTRICTION_LEVEL_RESTRICTED_BUCKET) { // Moved out of the background-restricted state. if (curBucket != STANDBY_BUCKET_RARE) { - synchronized (mLock) { + synchronized (mSettingsLock) { final int index = mActiveUids.indexOfKey(uid, pkgName); if (index >= 0) { mActiveUids.add(uid, pkgName, null); @@ -1437,7 +1450,7 @@ public final class AppRestrictionController { private void dispatchAutoRestrictedBucketFeatureFlagChanged(boolean newValue) { final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal(); final ArrayList<Runnable> pendingTasks = new ArrayList<>(); - synchronized (mLock) { + synchronized (mSettingsLock) { mRestrictionSettings.forEachUidLocked(uid -> { mRestrictionSettings.forEachPackageInUidLocked(uid, (pkgName, level, reason) -> { if (level == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) { @@ -1531,6 +1544,7 @@ public final class AppRestrictionController { private final NotificationManager mNotificationManager; private final Injector mInjector; private final Object mLock; + private final Object mSettingsLock; private final Context mContext; private final BroadcastReceiver mActionButtonReceiver = new BroadcastReceiver() { @@ -1551,7 +1565,7 @@ public final class AppRestrictionController { } }; - @GuardedBy("mLock") + @GuardedBy("mSettingsLock") private int mNotificationIDStepper = SUMMARY_NOTIFICATION_ID + 1; NotificationHelper(AppRestrictionController controller) { @@ -1559,6 +1573,7 @@ public final class AppRestrictionController { mInjector = controller.mInjector; mNotificationManager = mInjector.getNotificationManager(); mLock = controller.mLock; + mSettingsLock = controller.mSettingsLock; mContext = mInjector.getContext(); } @@ -1637,7 +1652,7 @@ public final class AppRestrictionController { int getNotificationIdIfNecessary(@NotificationType int notificationType, String packageName, int uid) { - synchronized (mLock) { + synchronized (mSettingsLock) { final RestrictionSettings.PkgSettings settings = mBgController.mRestrictionSettings .getRestrictionSettingsLocked(uid, packageName); if (settings == null) { @@ -1741,7 +1756,7 @@ public final class AppRestrictionController { } void cancelRequestBgRestrictedIfNecessary(String packageName, int uid) { - synchronized (mLock) { + synchronized (mSettingsLock) { final RestrictionSettings.PkgSettings settings = mBgController.mRestrictionSettings .getRestrictionSettingsLocked(uid, packageName); if (settings != null) { @@ -1755,7 +1770,7 @@ public final class AppRestrictionController { } void cancelLongRunningFGSNotificationIfNecessary(String packageName, int uid) { - synchronized (mLock) { + synchronized (mSettingsLock) { final RestrictionSettings.PkgSettings settings = mBgController.mRestrictionSettings .getRestrictionSettingsLocked(uid, packageName); if (settings != null) { @@ -1771,7 +1786,7 @@ public final class AppRestrictionController { void handleUidInactive(int uid, boolean disabled) { final ArrayList<Runnable> pendingTasks = mTmpRunnables; - synchronized (mLock) { + synchronized (mSettingsLock) { final int index = mActiveUids.indexOfKey(uid); if (index < 0) { return; @@ -1792,7 +1807,7 @@ public final class AppRestrictionController { } void handleUidActive(int uid) { - synchronized (mLock) { + synchronized (mSettingsLock) { final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal(); final int userId = UserHandle.getUserId(uid); mRestrictionSettings.forEachPackageInUidLocked(uid, (pkgName, level, reason) -> { diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index daf3561d75ce..ff7557a0eb6b 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -396,7 +396,8 @@ import java.util.concurrent.atomic.AtomicBoolean; AudioAttributes attr = AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( AudioSystem.STREAM_VOICE_CALL); - List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(attr); + List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes( + attr, false /* forVolume */); if (devices.isEmpty()) { if (mAudioService.isPlatformVoice()) { Log.w(TAG, diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 0b9fb1a72f8d..0ff8a93ce175 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1808,6 +1808,10 @@ public class AudioService extends IAudioService.Stub * @param caller caller of this method */ private void updateVolumeStates(int device, int streamType, String caller) { + // Handle device volume aliasing of SPEAKER_SAFE. + if (device == AudioSystem.DEVICE_OUT_SPEAKER_SAFE) { + device = AudioSystem.DEVICE_OUT_SPEAKER; + } if (!mStreamStates[streamType].hasIndexForDevice(device)) { // set the default value, if device is affected by a full/fix/abs volume rule, it // will taken into account in checkFixedVolumeDevices() @@ -1819,7 +1823,8 @@ public class AudioService extends IAudioService.Stub // Check if device to be updated is routed for the given audio stream List<AudioDeviceAttributes> devicesForAttributes = getDevicesForAttributesInt( - new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build()); + new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build(), + true /* forVolume */); for (AudioDeviceAttributes deviceAttributes : devicesForAttributes) { if (deviceAttributes.getType() == AudioDeviceInfo.convertInternalDeviceToDeviceType( device)) { @@ -2687,7 +2692,7 @@ public class AudioService extends IAudioService.Stub public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes( @NonNull AudioAttributes attributes) { enforceQueryStateOrModifyRoutingPermission(); - return getDevicesForAttributesInt(attributes); + return getDevicesForAttributesInt(attributes, false /* forVolume */); } /** @see AudioManager#getAudioDevicesForAttributes(AudioAttributes) @@ -2697,7 +2702,7 @@ public class AudioService extends IAudioService.Stub */ public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesUnprotected( @NonNull AudioAttributes attributes) { - return getDevicesForAttributesInt(attributes); + return getDevicesForAttributesInt(attributes, false /* forVolume */); } /** @@ -2719,9 +2724,9 @@ public class AudioService extends IAudioService.Stub } protected @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesInt( - @NonNull AudioAttributes attributes) { + @NonNull AudioAttributes attributes, boolean forVolume) { Objects.requireNonNull(attributes); - return mAudioSystem.getDevicesForAttributes(attributes); + return mAudioSystem.getDevicesForAttributes(attributes, forVolume); } /** Indicates no special treatment in the handling of the volume adjustement */ @@ -6490,7 +6495,8 @@ public class AudioService extends IAudioService.Stub .setUsage(AudioAttributes.USAGE_MEDIA) .build(); // calling getDevice*Int to bypass permission check - final List<AudioDeviceAttributes> devices = getDevicesForAttributesInt(attributes); + final List<AudioDeviceAttributes> devices = + getDevicesForAttributesInt(attributes, true /* forVolume */); for (AudioDeviceAttributes device : devices) { if (getDeviceVolumeBehaviorInt(device) == AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED) { return true; @@ -11273,6 +11279,7 @@ public class AudioService extends IAudioService.Stub @Override public void setActiveAssistantServiceUids(int [] activeAssistantUids) { enforceModifyAudioRoutingPermission(); + Objects.requireNonNull(activeAssistantUids); synchronized (mSettingsLock) { mActiveAssistantServiceUids = activeAssistantUids; } diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java index a70b4701bb7b..6ef8e876a10d 100644 --- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java +++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java @@ -24,12 +24,14 @@ import android.media.AudioSystem; import android.media.audiopolicy.AudioMix; import android.os.SystemClock; import android.util.Log; +import android.util.Pair; import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** @@ -59,7 +61,7 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback { private static final boolean USE_CACHE_FOR_GETDEVICES = true; private ConcurrentHashMap<Integer, Integer> mDevicesForStreamCache; - private ConcurrentHashMap<AudioAttributes, ArrayList<AudioDeviceAttributes>> + private ConcurrentHashMap<Pair<AudioAttributes, Boolean>, ArrayList<AudioDeviceAttributes>> mDevicesForAttrCache; private int[] mMethodCacheHit; private static final Object sRoutingListenerLock = new Object(); @@ -201,26 +203,28 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback { * @return the devices that the stream with the given attributes would be routed to */ public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes( - @NonNull AudioAttributes attributes) { + @NonNull AudioAttributes attributes, boolean forVolume) { if (!ENABLE_GETDEVICES_STATS) { - return getDevicesForAttributesImpl(attributes); + return getDevicesForAttributesImpl(attributes, forVolume); } mMethodCallCounter[METHOD_GETDEVICESFORATTRIBUTES]++; final long startTime = SystemClock.uptimeNanos(); - final ArrayList<AudioDeviceAttributes> res = getDevicesForAttributesImpl(attributes); + final ArrayList<AudioDeviceAttributes> res = getDevicesForAttributesImpl( + attributes, forVolume); mMethodTimeNs[METHOD_GETDEVICESFORATTRIBUTES] += SystemClock.uptimeNanos() - startTime; return res; } private @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesImpl( - @NonNull AudioAttributes attributes) { + @NonNull AudioAttributes attributes, boolean forVolume) { if (USE_CACHE_FOR_GETDEVICES) { ArrayList<AudioDeviceAttributes> res; + final Pair<AudioAttributes, Boolean> key = new Pair(attributes, forVolume); synchronized (mDevicesForAttrCache) { - res = mDevicesForAttrCache.get(attributes); + res = mDevicesForAttrCache.get(key); if (res == null) { - res = AudioSystem.getDevicesForAttributes(attributes); - mDevicesForAttrCache.put(attributes, res); + res = AudioSystem.getDevicesForAttributes(attributes, forVolume); + mDevicesForAttrCache.put(key, res); if (DEBUG_CACHE) { Log.d(TAG, mMethodNames[METHOD_GETDEVICESFORATTRIBUTES] + attrDeviceToDebugString(attributes, res)); @@ -231,7 +235,7 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback { mMethodCacheHit[METHOD_GETDEVICESFORATTRIBUTES]++; if (DEBUG_CACHE) { final ArrayList<AudioDeviceAttributes> real = - AudioSystem.getDevicesForAttributes(attributes); + AudioSystem.getDevicesForAttributes(attributes, forVolume); if (res.equals(real)) { Log.d(TAG, mMethodNames[METHOD_GETDEVICESFORATTRIBUTES] + attrDeviceToDebugString(attributes, res) + " CACHE"); @@ -245,7 +249,7 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback { return res; } // not using cache - return AudioSystem.getDevicesForAttributes(attributes); + return AudioSystem.getDevicesForAttributes(attributes, forVolume); } private static String attrDeviceToDebugString(@NonNull AudioAttributes attr, @@ -523,9 +527,10 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback { } pw.println(" mDevicesForAttrCache:"); if (mDevicesForAttrCache != null) { - for (AudioAttributes attr : mDevicesForAttrCache.keySet()) { - pw.println("\t" + attr); - for (AudioDeviceAttributes devAttr : mDevicesForAttrCache.get(attr)) { + for (Map.Entry<Pair<AudioAttributes, Boolean>, ArrayList<AudioDeviceAttributes>> + entry : mDevicesForAttrCache.entrySet()) { + pw.println("\t" + entry.getKey().first + " forVolume: " + entry.getKey().second); + for (AudioDeviceAttributes devAttr : entry.getValue()) { pw.println("\t\t" + devAttr); } } diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java index 63b27d82dab9..193cc5f679af 100644 --- a/services/core/java/com/android/server/audio/SpatializerHelper.java +++ b/services/core/java/com/android/server/audio/SpatializerHelper.java @@ -264,7 +264,8 @@ public class SpatializerHelper { return; } mState = STATE_DISABLED_UNAVAILABLE; - mASA.getDevicesForAttributes(DEFAULT_ATTRIBUTES).toArray(ROUTING_DEVICES); + mASA.getDevicesForAttributes( + DEFAULT_ATTRIBUTES, false /* forVolume */).toArray(ROUTING_DEVICES); // note at this point mSpat is still not instantiated } @@ -298,7 +299,8 @@ public class SpatializerHelper { case STATE_DISABLED_AVAILABLE: break; } - mASA.getDevicesForAttributes(DEFAULT_ATTRIBUTES).toArray(ROUTING_DEVICES); + mASA.getDevicesForAttributes( + DEFAULT_ATTRIBUTES, false /* forVolume */).toArray(ROUTING_DEVICES); // is media routed to a new device? if (isWireless(ROUTING_DEVICES[0].getType())) { @@ -865,7 +867,8 @@ public class SpatializerHelper { } AudioDeviceAttributes[] devices = new AudioDeviceAttributes[1]; // going through adapter to take advantage of routing cache - mASA.getDevicesForAttributes(attributes).toArray(devices); + mASA.getDevicesForAttributes( + attributes, false /* forVolume */).toArray(devices); final boolean able = canBeSpatializedOnDevice(attributes, format, devices); logd("canBeSpatialized returning " + able); return able; diff --git a/services/core/java/com/android/server/audio/TEST_MAPPING b/services/core/java/com/android/server/audio/TEST_MAPPING index 5a6c6a51bd97..f3a73f043c29 100644 --- a/services/core/java/com/android/server/audio/TEST_MAPPING +++ b/services/core/java/com/android/server/audio/TEST_MAPPING @@ -8,6 +8,9 @@ }, { "include-filter": "android.media.audio.cts.AudioFocusTest" + }, + { + "include-filter": "android.media.audio.cts.SpatializerTest" } ] } diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java b/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java index 812ca8ac62fe..15f0cadced99 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java @@ -84,6 +84,8 @@ public class BiometricSchedulerOperation { private final BaseClientMonitor mClientMonitor; @Nullable private final ClientMonitorCallback mClientCallback; + @Nullable + private ClientMonitorCallback mOnStartCallback; @OperationState private int mState; @VisibleForTesting @@ -108,7 +110,8 @@ public class BiometricSchedulerOperation { mCancelWatchdog = () -> { if (!isFinished()) { Slog.e(TAG, "[Watchdog Triggered]: " + this); - getWrappedCallback().onClientFinished(mClientMonitor, false /* success */); + getWrappedCallback(mOnStartCallback) + .onClientFinished(mClientMonitor, false /* success */); } }; } @@ -174,6 +177,7 @@ public class BiometricSchedulerOperation { } private boolean doStart(@NonNull ClientMonitorCallback callback) { + mOnStartCallback = callback; final ClientMonitorCallback cb = getWrappedCallback(callback); if (mState == STATE_WAITING_IN_QUEUE_CANCELING) { diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index a7b49f1e51b0..9bfdd687644b 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -2463,7 +2463,7 @@ public final class DisplayManagerService extends SystemService { pw.println(" mMinimumBrightnessCurve=" + mMinimumBrightnessCurve); if (mUserPreferredMode != null) { - pw.println(mUserPreferredMode); + pw.println(" mUserPreferredMode=" + mUserPreferredMode); } pw.println(); diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 2e80efb957d4..7a0cf4b592e7 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -884,20 +884,26 @@ final class LocalDisplayAdapter extends DisplayAdapter { public void setUserPreferredDisplayModeLocked(Display.Mode mode) { final int oldModeId = getPreferredModeId(); mUserPreferredMode = mode; - if (mode != null && (mode.isRefreshRateSet() ^ mode.isResolutionSet())) { - mUserPreferredMode = findMode(mode.getPhysicalWidth(), + if (mode != null && (mode.isRefreshRateSet() || mode.isResolutionSet())) { + Display.Mode matchingSupportedMode; + matchingSupportedMode = findMode(mode.getPhysicalWidth(), mode.getPhysicalHeight(), mode.getRefreshRate()); + if (matchingSupportedMode != null) { + mUserPreferredMode = matchingSupportedMode; + } } - mUserPreferredModeId = findUserPreferredModeIdLocked(mode); - if (oldModeId != getPreferredModeId()) { - updateDeviceInfoLocked(); + mUserPreferredModeId = findUserPreferredModeIdLocked(mUserPreferredMode); + + if (oldModeId == getPreferredModeId()) { + return; } + updateDeviceInfoLocked(); if (!mSurfaceControlProxy.getBootDisplayModeSupport()) { return; } - if (mUserPreferredMode == null) { + if (mUserPreferredModeId == INVALID_MODE_ID) { mSurfaceControlProxy.clearBootDisplayMode(getDisplayTokenLocked()); } else { int preferredSfDisplayModeId = findSfDisplayModeIdLocked( diff --git a/services/core/java/com/android/server/infra/OWNERS b/services/core/java/com/android/server/infra/OWNERS new file mode 100644 index 000000000000..0466d8a88053 --- /dev/null +++ b/services/core/java/com/android/server/infra/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 655446 + +include /core/java/android/service/cloudsearch/OWNERS diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java index c42770555bab..176c08c8da29 100644 --- a/services/core/java/com/android/server/locales/LocaleManagerService.java +++ b/services/core/java/com/android/server/locales/LocaleManagerService.java @@ -78,10 +78,20 @@ public class LocaleManagerService extends SystemService { Process.THREAD_PRIORITY_BACKGROUND); broadcastHandlerThread.start(); + SystemAppUpdateTracker systemAppUpdateTracker = + new SystemAppUpdateTracker(this); + broadcastHandlerThread.getThreadHandler().postAtFrontOfQueue(new Runnable() { + @Override + public void run() { + systemAppUpdateTracker.init(); + } + }); + mBackupHelper = new LocaleManagerBackupHelper(this, mPackageManagerInternal, broadcastHandlerThread); - mPackageMonitor = new LocaleManagerServicePackageMonitor(mBackupHelper); + mPackageMonitor = new LocaleManagerServicePackageMonitor(mBackupHelper, + systemAppUpdateTracker); mPackageMonitor.register(context, broadcastHandlerThread.getLooper(), UserHandle.ALL, true); @@ -246,7 +256,7 @@ public class LocaleManagerService extends SystemService { * <p><b>Note:</b> This is can be used by installers to deal with cases such as * language-based APK Splits. */ - private void notifyInstallerOfAppWhoseLocaleChanged(String appPackageName, int userId, + void notifyInstallerOfAppWhoseLocaleChanged(String appPackageName, int userId, LocaleList locales) { String installingPackageName = getInstallingPackageName(appPackageName); if (installingPackageName != null) { @@ -271,7 +281,7 @@ public class LocaleManagerService extends SystemService { mContext.sendBroadcastAsUser(intent, UserHandle.of(userId)); } - private static Intent createBaseIntent(String intentAction, String appPackageName, + static Intent createBaseIntent(String intentAction, String appPackageName, LocaleList locales) { return new Intent(intentAction) .putExtra(Intent.EXTRA_PACKAGE_NAME, appPackageName) @@ -406,7 +416,7 @@ public class LocaleManagerService extends SystemService { } @Nullable - private String getInstallingPackageName(String packageName) { + String getInstallingPackageName(String packageName) { try { return mContext.getPackageManager() .getInstallSourceInfo(packageName).getInstallingPackageName(); diff --git a/services/core/java/com/android/server/locales/LocaleManagerServicePackageMonitor.java b/services/core/java/com/android/server/locales/LocaleManagerServicePackageMonitor.java index b459be768b9f..32080ef356ae 100644 --- a/services/core/java/com/android/server/locales/LocaleManagerServicePackageMonitor.java +++ b/services/core/java/com/android/server/locales/LocaleManagerServicePackageMonitor.java @@ -23,13 +23,22 @@ import com.android.internal.content.PackageMonitor; * * <p> These listeners forward the call to different aspects of locale service that * handle the business logic. - * <p> We're interested in package added, package data cleared and package removed events. + * <p> We're interested in the following events: + * <ul> + * <li> Package added + * <li> Package data cleared + * <li> Package removed + * <li> Package Updated + * </ul> */ final class LocaleManagerServicePackageMonitor extends PackageMonitor { private LocaleManagerBackupHelper mBackupHelper; + private SystemAppUpdateTracker mSystemAppUpdateTracker; - LocaleManagerServicePackageMonitor(LocaleManagerBackupHelper localeManagerBackupHelper) { + LocaleManagerServicePackageMonitor(LocaleManagerBackupHelper localeManagerBackupHelper, + SystemAppUpdateTracker systemAppUpdateTracker) { mBackupHelper = localeManagerBackupHelper; + mSystemAppUpdateTracker = systemAppUpdateTracker; } @Override @@ -46,4 +55,9 @@ final class LocaleManagerServicePackageMonitor extends PackageMonitor { public void onPackageRemoved(String packageName, int uid) { mBackupHelper.onPackageRemoved(); } + + @Override + public void onPackageUpdateFinished(String packageName, int uid) { + mSystemAppUpdateTracker.onPackageUpdateFinished(packageName, uid); + } } diff --git a/services/core/java/com/android/server/locales/SystemAppUpdateTracker.java b/services/core/java/com/android/server/locales/SystemAppUpdateTracker.java new file mode 100644 index 000000000000..d13b1f4d2845 --- /dev/null +++ b/services/core/java/com/android/server/locales/SystemAppUpdateTracker.java @@ -0,0 +1,249 @@ +/* + * 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.locales; + +import static com.android.server.locales.LocaleManagerService.DEBUG; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Environment; +import android.os.LocaleList; +import android.os.RemoteException; +import android.os.UserHandle; +import android.text.TextUtils; +import android.util.AtomicFile; +import android.util.Slog; +import android.util.TypedXmlPullParser; +import android.util.TypedXmlSerializer; +import android.util.Xml; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.XmlUtils; + +import libcore.io.IoUtils; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Set; + +/** + * Track if a system app is being updated for the first time after the user completed device setup. + * + * <p> The entire operation is being done on a background thread from {@link LocaleManagerService}. + * If it is the first time that a system app is being updated, then it fetches the app-specific + * locales and sends a broadcast to the newly set installer of the app. It maintains a file to store + * the name of the apps that have been updated. + */ +public class SystemAppUpdateTracker { + private static final String TAG = "SystemAppUpdateTracker"; + private static final String PACKAGE_XML_TAG = "package"; + private static final String ATTR_NAME = "name"; + private static final String SYSTEM_APPS_XML_TAG = "system_apps"; + + private final Context mContext; + private final LocaleManagerService mLocaleManagerService; + private final AtomicFile mUpdatedAppsFile; + + // Lock used while writing to the file. + private final Object mFileLock = new Object(); + + // In-memory list of all the system apps that have been updated once after device setup. + // We do not need to store the userid->packages mapping because when updating a system app on + // one user updates for all users. + private final Set<String> mUpdatedApps = new HashSet<>(); + + SystemAppUpdateTracker(LocaleManagerService localeManagerService) { + this(localeManagerService.mContext, localeManagerService, new AtomicFile( + new File(Environment.getDataSystemDirectory(), + /* child = */ "locale_manager_service_updated_system_apps.xml"))); + } + + @VisibleForTesting + SystemAppUpdateTracker(Context context, LocaleManagerService localeManagerService, + AtomicFile file) { + mContext = context; + mLocaleManagerService = localeManagerService; + mUpdatedAppsFile = file; + } + + /** + * Loads the info of updated system apps from the file. + * + * <p> Invoked once during device boot from {@link LocaleManagerService} by a background thread. + */ + void init() { + if (DEBUG) { + Slog.d(TAG, "Loading the app info from storage. "); + } + loadUpdatedSystemApps(); + } + + /** + * Reads the XML stored in the {@link #mUpdatedAppsFile} and populates it in the in-memory list + * {@link #mUpdatedApps}. + */ + private void loadUpdatedSystemApps() { + if (!mUpdatedAppsFile.getBaseFile().exists()) { + if (DEBUG) { + Slog.d(TAG, "loadUpdatedSystemApps: File does not exist."); + } + return; + } + InputStream updatedAppNamesInputStream = null; + try { + updatedAppNamesInputStream = mUpdatedAppsFile.openRead(); + readFromXml(updatedAppNamesInputStream); + } catch (IOException | XmlPullParserException e) { + Slog.e(TAG, "loadUpdatedSystemApps: Could not parse storage file ", e); + } finally { + IoUtils.closeQuietly(updatedAppNamesInputStream); + } + } + + /** + * Parses the update data from the serialized XML input stream. + */ + private void readFromXml(InputStream updateInfoInputStream) + throws XmlPullParserException, IOException { + final TypedXmlPullParser parser = Xml.newFastPullParser(); + parser.setInput(updateInfoInputStream, StandardCharsets.UTF_8.name()); + XmlUtils.beginDocument(parser, SYSTEM_APPS_XML_TAG); + int depth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, depth)) { + if (parser.getName().equals(PACKAGE_XML_TAG)) { + String packageName = parser.getAttributeValue(/* namespace= */ null, + ATTR_NAME); + if (!TextUtils.isEmpty(packageName)) { + mUpdatedApps.add(packageName); + } + } + } + } + + /** + * Sends a broadcast to the newly set installer with app-locales if it is a system app being + * updated for the first time. + * + * <p><b>Note:</b> Invoked by service's common monitor + * {@link LocaleManagerServicePackageMonitor#onPackageUpdateFinished} when a package updated. + */ + void onPackageUpdateFinished(String packageName, int uid) { + try { + if ((!mUpdatedApps.contains(packageName)) && isUpdatedSystemApp(packageName)) { + // If a system app is updated, verify that it has an installer-on-record. + String installingPackageName = mLocaleManagerService.getInstallingPackageName( + packageName); + if (installingPackageName == null) { + // We want to broadcast the locales info to the installer. + // If this app does not have an installer then do nothing. + return; + } + + try { + int userId = UserHandle.getUserId(uid); + // Fetch the app-specific locales. + // If non-empty then send the info to the installer. + LocaleList appLocales = mLocaleManagerService.getApplicationLocales( + packageName, userId); + if (!appLocales.isEmpty()) { + // The broadcast would be sent to the newly set installer of the + // updated system app. + mLocaleManagerService.notifyInstallerOfAppWhoseLocaleChanged(packageName, + userId, appLocales); + } + } catch (RemoteException e) { + if (DEBUG) { + Slog.d(TAG, "onPackageUpdateFinished: Error in fetching app locales"); + } + } + updateBroadcastedAppsList(packageName); + } + } catch (Exception e) { + Slog.e(TAG, "Exception in onPackageUpdateFinished.", e); + } + } + + /** + * Writes in-memory data {@link #mUpdatedApps} to the storage file in a synchronized manner. + */ + private void updateBroadcastedAppsList(String packageName) { + synchronized (mFileLock) { + mUpdatedApps.add(packageName); + writeUpdatedAppsFileLocked(); + } + } + + private void writeUpdatedAppsFileLocked() { + FileOutputStream stream = null; + try { + stream = mUpdatedAppsFile.startWrite(); + writeToXmlLocked(stream); + mUpdatedAppsFile.finishWrite(stream); + } catch (IOException e) { + mUpdatedAppsFile.failWrite(stream); + Slog.e(TAG, "Failed to persist the updated apps list", e); + } + } + + /** + * Converts the list of updated app data into a serialized xml stream. + */ + private void writeToXmlLocked(OutputStream stream) throws IOException { + final TypedXmlSerializer xml = Xml.newFastSerializer(); + xml.setOutput(stream, StandardCharsets.UTF_8.name()); + xml.startDocument(/* encoding= */ null, /* standalone= */ true); + xml.startTag(/* namespace= */ null, SYSTEM_APPS_XML_TAG); + + for (String packageName : mUpdatedApps) { + xml.startTag(/* namespace= */ null, PACKAGE_XML_TAG); + xml.attribute(/* namespace= */ null, ATTR_NAME, packageName); + xml.endTag(/* namespace= */ null, PACKAGE_XML_TAG); + } + + xml.endTag(null, SYSTEM_APPS_XML_TAG); + xml.endDocument(); + } + + private boolean isUpdatedSystemApp(String packageName) { + ApplicationInfo appInfo = null; + try { + appInfo = mContext.getPackageManager().getApplicationInfo(packageName, + PackageManager.ApplicationInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY)); + } catch (PackageManager.NameNotFoundException e) { + if (DEBUG) { + Slog.d(TAG, "isUpdatedSystemApp: Package not found " + packageName); + } + } + if (appInfo == null) { + return false; + } + return (appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; + } + + @VisibleForTesting + Set<String> getUpdatedApps() { + return mUpdatedApps; + } +} diff --git a/services/core/java/com/android/server/location/geofence/GeofenceManager.java b/services/core/java/com/android/server/location/geofence/GeofenceManager.java index 5093f5dee55e..b6342a472023 100644 --- a/services/core/java/com/android/server/location/geofence/GeofenceManager.java +++ b/services/core/java/com/android/server/location/geofence/GeofenceManager.java @@ -19,7 +19,6 @@ package com.android.server.location.geofence; import static android.location.LocationManager.FUSED_PROVIDER; import static android.location.LocationManager.KEY_PROXIMITY_ENTERING; -import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; import static com.android.server.location.LocationPermissions.PERMISSION_FINE; import android.annotation.Nullable; @@ -41,6 +40,7 @@ import android.stats.location.LocationStatsEnums; import android.util.ArraySet; import com.android.internal.annotations.GuardedBy; +import com.android.server.FgThread; import com.android.server.PendingIntentUtils; import com.android.server.location.LocationPermissions; import com.android.server.location.injector.Injector; @@ -396,7 +396,7 @@ public class GeofenceManager extends protected boolean registerWithService(LocationRequest locationRequest, Collection<GeofenceRegistration> registrations) { getLocationManager().requestLocationUpdates(FUSED_PROVIDER, locationRequest, - DIRECT_EXECUTOR, this); + FgThread.getExecutor(), this); return true; } diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java index acbee11f3b72..721ef1ed358f 100644 --- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java @@ -201,18 +201,54 @@ public class LocationProviderManager extends @Override public void deliverOnLocationChanged(LocationResult locationResult, @Nullable IRemoteCallback onCompleteCallback) throws RemoteException { - mListener.onLocationChanged(locationResult.asList(), onCompleteCallback); + try { + mListener.onLocationChanged(locationResult.asList(), onCompleteCallback); + } catch (RuntimeException e) { + // the only way a runtime exception can be thrown here is if the client is in the + // system server process (so that the binder call is executed directly, rather than + // asynchronously in another process), and the client is using a direct executor (so + // any client exceptions bubble directly back to us). we move any exception onto + // another thread so that it can't cause further problems + RuntimeException wrapper = new RuntimeException(e); + FgThread.getExecutor().execute(() -> { + throw wrapper; + }); + } } @Override public void deliverOnFlushComplete(int requestCode) throws RemoteException { - mListener.onFlushComplete(requestCode); + try { + mListener.onFlushComplete(requestCode); + } catch (RuntimeException e) { + // the only way a runtime exception can be thrown here is if the client is in the + // system server process (so that the binder call is executed directly, rather than + // asynchronously in another process), and the client is using a direct executor (so + // any client exceptions bubble directly back to us). we move any exception onto + // another thread so that it can't cause further problems + RuntimeException wrapper = new RuntimeException(e); + FgThread.getExecutor().execute(() -> { + throw wrapper; + }); + } } @Override public void deliverOnProviderEnabledChanged(String provider, boolean enabled) throws RemoteException { - mListener.onProviderEnabledChanged(provider, enabled); + try { + mListener.onProviderEnabledChanged(provider, enabled); + } catch (RuntimeException e) { + // the only way a runtime exception can be thrown here is if the client is in the + // system server process (so that the binder call is executed directly, rather than + // asynchronously in another process), and the client is using a direct executor (so + // any client exceptions bubble directly back to us). we move any exception onto + // another thread so that it can't cause further problems + RuntimeException wrapper = new RuntimeException(e); + FgThread.getExecutor().execute(() -> { + throw wrapper; + }); + } } } @@ -294,10 +330,23 @@ public class LocationProviderManager extends throws RemoteException { // ILocationCallback doesn't currently support completion callbacks Preconditions.checkState(onCompleteCallback == null); - if (locationResult != null) { - mCallback.onLocation(locationResult.getLastLocation()); - } else { - mCallback.onLocation(null); + + try { + if (locationResult != null) { + mCallback.onLocation(locationResult.getLastLocation()); + } else { + mCallback.onLocation(null); + } + } catch (RuntimeException e) { + // the only way a runtime exception can be thrown here is if the client is in the + // system server process (so that the binder call is executed directly, rather than + // asynchronously in another process), and the client is using a direct executor (so + // any client exceptions bubble directly back to us). we move any exception onto + // another thread so that it can't cause further problems + RuntimeException wrapper = new RuntimeException(e); + FgThread.getExecutor().execute(() -> { + throw wrapper; + }); } } diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java index 9cb8a0105286..4f2680904fae 100644 --- a/services/core/java/com/android/server/notification/GroupHelper.java +++ b/services/core/java/com/android/server/notification/GroupHelper.java @@ -82,7 +82,7 @@ public class GroupHelper { } String combinedKey = generatePackageGroupKey(userId, sbn.getPackageName(), group); boolean needsOngoingFlag = notifications.size() > 0; - mCallback.updateAutogroupSummary(sbn.getKey(), needsOngoingFlag); + mCallback.updateAutogroupSummary(userId, sbn.getPackageName(), needsOngoingFlag); } public void onNotificationUpdated(StatusBarNotification childSbn, @@ -211,6 +211,6 @@ public class GroupHelper { void removeAutoGroup(String key); void addAutoGroupSummary(int userId, String pkg, String triggeringKey); void removeAutoGroupSummary(int user, String pkg); - void updateAutogroupSummary(String key, boolean needsOngoingFlag); + void updateAutogroupSummary(int userId, String pkg, boolean needsOngoingFlag); } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index a711b442c450..050cfeae80b9 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2587,19 +2587,11 @@ public class NotificationManagerService extends SystemService { } @Override - public void updateAutogroupSummary(String key, boolean needsOngoingFlag) { - String pkg; - synchronized (mNotificationLock) { - NotificationRecord r = mNotificationsByKey.get(key); - pkg = r != null && r.getSbn() != null ? r.getSbn().getPackageName() : null; - } + public void updateAutogroupSummary(int userId, String pkg, boolean needsOngoingFlag) { boolean isAppForeground = pkg != null && mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; synchronized (mNotificationLock) { - NotificationRecord r = mNotificationsByKey.get(key); - if (r == null) return; - updateAutobundledSummaryFlags(r.getUser().getIdentifier(), - r.getSbn().getPackageName(), needsOngoingFlag, isAppForeground); + updateAutobundledSummaryFlags(userId, pkg, needsOngoingFlag, isAppForeground); } } }); diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index b03db66fde94..dcfb8b5e7b33 100644 --- a/services/core/java/com/android/server/power/ShutdownThread.java +++ b/services/core/java/com/android/server/power/ShutdownThread.java @@ -315,15 +315,15 @@ public final class ShutdownThread extends Thread { com.android.internal.R.string.reboot_to_update_reboot)); } } else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) { - if (showSysuiReboot()) { - return null; - } else if (RescueParty.isAttemptingFactoryReset()) { + if (RescueParty.isAttemptingFactoryReset()) { // We're not actually doing a factory reset yet; we're rebooting // to ask the user if they'd like to reset, so give them a less // scary dialog message. pd.setTitle(context.getText(com.android.internal.R.string.power_off)); pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress)); pd.setIndeterminate(true); + } else if (showSysuiReboot()) { + return null; } else { // Factory reset path. Set the dialog message accordingly. pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title)); diff --git a/services/core/java/com/android/server/security/AndroidKeystoreAttestationVerificationAttributes.java b/services/core/java/com/android/server/security/AndroidKeystoreAttestationVerificationAttributes.java new file mode 100644 index 000000000000..3543e9319a88 --- /dev/null +++ b/services/core/java/com/android/server/security/AndroidKeystoreAttestationVerificationAttributes.java @@ -0,0 +1,468 @@ +/* + * 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.security; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import com.android.framework.protobuf.ByteString; +import com.android.internal.org.bouncycastle.asn1.ASN1Boolean; +import com.android.internal.org.bouncycastle.asn1.ASN1Encodable; +import com.android.internal.org.bouncycastle.asn1.ASN1Enumerated; +import com.android.internal.org.bouncycastle.asn1.ASN1InputStream; +import com.android.internal.org.bouncycastle.asn1.ASN1Integer; +import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.internal.org.bouncycastle.asn1.ASN1OctetString; +import com.android.internal.org.bouncycastle.asn1.ASN1Sequence; +import com.android.internal.org.bouncycastle.asn1.ASN1Set; +import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject; +import com.android.internal.org.bouncycastle.asn1.x509.Certificate; + +import java.nio.charset.StandardCharsets; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Parsed {@link X509Certificate} attestation extension values for Android Keystore attestations. + * + * Pull fields out of the top-level sequence. A full description of this structure is at + * https://source.android.com/security/keystore/attestation. + * + * If a value is null or empty, then it was not set/found in the extension values. + * + */ +class AndroidKeystoreAttestationVerificationAttributes { + // The OID for the extension Android Keymaster puts into device-generated certificates. + private static final String ANDROID_KEYMASTER_KEY_DESCRIPTION_EXTENSION_OID = + "1.3.6.1.4.1.11129.2.1.17"; + + // ASN.1 sequence index values for the Android Keymaster extension. + private static final int ATTESTATION_VERSION_INDEX = 0; + private static final int ATTESTATION_SECURITY_LEVEL_INDEX = 1; + private static final int KEYMASTER_VERSION_INDEX = 2; + private static final int KEYMASTER_SECURITY_LEVEL_INDEX = 3; + private static final int ATTESTATION_CHALLENGE_INDEX = 4; + private static final int KEYMASTER_UNIQUE_ID_INDEX = 5; + private static final int SW_ENFORCED_INDEX = 6; + private static final int HW_ENFORCED_INDEX = 7; + private static final int VERIFIED_BOOT_KEY_INDEX = 0; + private static final int VERIFIED_BOOT_LOCKED_INDEX = 1; + private static final int VERIFIED_BOOT_STATE_INDEX = 2; + private static final int VERIFIED_BOOT_HASH_INDEX = 3; + + // ASN.1 sequence index values for the Android Keystore application id. + private static final int PACKAGE_INFO_SET_INDEX = 0; + private static final int PACKAGE_SIGNATURE_SET_INDEX = 1; + private static final int PACKAGE_INFO_NAME_INDEX = 0; + private static final int PACKAGE_INFO_VERSION_INDEX = 1; + + // See these AOSP files: hardware/libhardware/include/hardware/hw_auth_token.h + private static final int HW_AUTH_NONE = 0; + + // Some keymaster constants. See this AOSP file: + // hardware/libhardware/include/hardware/keymaster_defs.h + private static final int KM_TAG_NO_AUTH_REQUIRED = 503; + private static final int KM_TAG_UNLOCKED_DEVICE_REQUIRED = 509; + private static final int KM_TAG_ALL_APPLICATIONS = 600; + private static final int KM_TAG_ROOT_OF_TRUST = 704; + private static final int KM_TAG_OS_VERSION = 705; + private static final int KM_TAG_OS_PATCHLEVEL = 706; + private static final int KM_TAG_ATTESTATION_APPLICATION_ID = 709; + private static final int KM_TAG_ATTESTATION_ID_BRAND = 710; + private static final int KM_TAG_ATTESTATION_ID_DEVICE = 711; + private static final int KM_TAG_ATTESTATION_ID_PRODUCT = 712; + private static final int KM_TAG_VENDOR_PATCHLEVEL = 718; + private static final int KM_TAG_BOOT_PATCHLEVEL = 719; + + private static final int KM_SECURITY_LEVEL_SOFTWARE = 0; + private static final int KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1; + private static final int KM_SECURITY_LEVEL_STRONG_BOX = 2; + private static final int KM_VERIFIED_BOOT_STATE_VERIFIED = 0; + private static final int KM_VERIFIED_BOOT_STATE_SELF_SIGNED = 1; + private static final int KM_VERIFIED_BOOT_STATE_UNVERIFIED = 2; + private static final int KM_VERIFIED_BOOT_STATE_FAILED = 3; + + private Integer mAttestationVersion = null; + private SecurityLevel mAttestationSecurityLevel = null; + private boolean mAttestationHardwareBacked = false; + private Integer mKeymasterVersion = null; + private SecurityLevel mKeymasterSecurityLevel = null; + private boolean mKeymasterHardwareBacked = false; + private ByteString mAttestationChallenge = null; + private ByteString mKeymasterUniqueId = null; + private String mDeviceBrand = null; + private String mDeviceName = null; + private String mDeviceProductName = null; + private boolean mKeyAllowedForAllApplications = false; + private Integer mKeyAuthenticatorType = null; + private Integer mKeyBootPatchLevel = null; + private Integer mKeyOsPatchLevel = null; + private Integer mKeyOsVersion = null; + private Integer mKeyVendorPatchLevel = null; + private Boolean mKeyRequiresUnlockedDevice = null; + private ByteString mVerifiedBootHash = null; + private ByteString mVerifiedBootKey = null; + private Boolean mVerifiedBootLocked = null; + private VerifiedBootState mVerifiedBootState = null; + private Map<String, Long> mApplicationPackageNameVersion = null; + private List<ByteString> mApplicationCertificateDigests = null; + + enum VerifiedBootState { + VERIFIED, + SELF_SIGNED, + UNVERIFIED, + FAILED + } + + enum SecurityLevel { + SOFTWARE, + TRUSTED_ENVIRONMENT, + STRONG_BOX + } + + /** + * Extracts attestation extension properties from {@link X509Certificate} + * and returns a {@link AndroidKeystoreAttestationVerificationAttributes} that encapsulates the + * properties. + */ + @NonNull + static AndroidKeystoreAttestationVerificationAttributes fromCertificate( + @NonNull X509Certificate x509Certificate) + throws Exception { + return new AndroidKeystoreAttestationVerificationAttributes(x509Certificate); + } + + int getAttestationVersion() { + return mAttestationVersion; + } + + @Nullable + SecurityLevel getAttestationSecurityLevel() { + return mAttestationSecurityLevel; + } + + boolean isAttestationHardwareBacked() { + return mAttestationHardwareBacked; + } + + int getKeymasterVersion() { + return mKeymasterVersion; + } + + @Nullable + SecurityLevel getKeymasterSecurityLevel() { + return mKeymasterSecurityLevel; + } + + boolean isKeymasterHardwareBacked() { + return mKeymasterHardwareBacked; + } + + @Nullable + ByteString getAttestationChallenge() { + return mAttestationChallenge; + } + + @Nullable + ByteString getKeymasterUniqueId() { + return mKeymasterUniqueId; + } + + @Nullable + String getDeviceBrand() { + return mDeviceBrand; + } + + @Nullable + String getDeviceName() { + return mDeviceName; + } + + @Nullable + String getDeviceProductName() { + return mDeviceProductName; + } + + boolean isKeyAllowedForAllApplications() { + return mKeyAllowedForAllApplications; + } + + int getKeyAuthenticatorType() { + if (mKeyAuthenticatorType == null) { + throw new IllegalStateException("KeyAuthenticatorType is not set."); + } + return mKeyAuthenticatorType; + } + + int getKeyBootPatchLevel() { + if (mKeyBootPatchLevel == null) { + throw new IllegalStateException("KeyBootPatchLevel is not set."); + } + return mKeyBootPatchLevel; + } + + int getKeyOsPatchLevel() { + if (mKeyOsPatchLevel == null) { + throw new IllegalStateException("KeyOsPatchLevel is not set."); + } + return mKeyOsPatchLevel; + } + + int getKeyVendorPatchLevel() { + if (mKeyVendorPatchLevel == null) { + throw new IllegalStateException("KeyVendorPatchLevel is not set."); + } + return mKeyVendorPatchLevel; + } + + int getKeyOsVersion() { + if (mKeyOsVersion == null) { + throw new IllegalStateException("KeyOsVersion is not set."); + } + return mKeyOsVersion; + } + + boolean isKeyRequiresUnlockedDevice() { + if (mKeyRequiresUnlockedDevice == null) { + throw new IllegalStateException("KeyRequiresUnlockedDevice is not set."); + } + return mKeyRequiresUnlockedDevice; + } + + @Nullable + ByteString getVerifiedBootHash() { + return mVerifiedBootHash; + } + + @Nullable + ByteString getVerifiedBootKey() { + return mVerifiedBootKey; + } + + boolean isVerifiedBootLocked() { + if (mVerifiedBootLocked == null) { + throw new IllegalStateException("VerifiedBootLocked is not set."); + } + return mVerifiedBootLocked; + } + + @Nullable + VerifiedBootState getVerifiedBootState() { + return mVerifiedBootState; + } + + @Nullable + Map<String, Long> getApplicationPackageNameVersion() { + return Collections.unmodifiableMap(mApplicationPackageNameVersion); + } + + @Nullable + List<ByteString> getApplicationCertificateDigests() { + return Collections.unmodifiableList(mApplicationCertificateDigests); + } + + private AndroidKeystoreAttestationVerificationAttributes(X509Certificate x509Certificate) + throws Exception { + Certificate certificate = Certificate.getInstance( + new ASN1InputStream(x509Certificate.getEncoded()).readObject()); + ASN1Sequence keyAttributes = (ASN1Sequence) certificate.getTBSCertificate().getExtensions() + .getExtensionParsedValue( + new ASN1ObjectIdentifier(ANDROID_KEYMASTER_KEY_DESCRIPTION_EXTENSION_OID)); + if (keyAttributes == null) { + throw new CertificateEncodingException( + "No attestation extension found in certificate."); + } + this.mAttestationVersion = getIntegerFromAsn1( + keyAttributes.getObjectAt(ATTESTATION_VERSION_INDEX)); + this.mAttestationSecurityLevel = getSecurityLevelEnum( + keyAttributes.getObjectAt(ATTESTATION_SECURITY_LEVEL_INDEX)); + this.mAttestationHardwareBacked = + this.mAttestationSecurityLevel == SecurityLevel.TRUSTED_ENVIRONMENT; + this.mAttestationChallenge = getOctetsFromAsn1( + keyAttributes.getObjectAt(ATTESTATION_CHALLENGE_INDEX)); + this.mKeymasterVersion = getIntegerFromAsn1( + keyAttributes.getObjectAt(KEYMASTER_VERSION_INDEX)); + this.mKeymasterUniqueId = getOctetsFromAsn1( + keyAttributes.getObjectAt(KEYMASTER_UNIQUE_ID_INDEX)); + this.mKeymasterSecurityLevel = getSecurityLevelEnum( + keyAttributes.getObjectAt(KEYMASTER_SECURITY_LEVEL_INDEX)); + this.mKeymasterHardwareBacked = + this.mKeymasterSecurityLevel == SecurityLevel.TRUSTED_ENVIRONMENT; + + ASN1Encodable[] softwareEnforced = ((ASN1Sequence) + keyAttributes.getObjectAt(SW_ENFORCED_INDEX)).toArray(); + for (ASN1Encodable entry : softwareEnforced) { + ASN1TaggedObject taggedEntry = (ASN1TaggedObject) entry; + switch (taggedEntry.getTagNo()) { + case KM_TAG_ATTESTATION_APPLICATION_ID: + parseAttestationApplicationId( + getOctetsFromAsn1(taggedEntry.getObject()).toByteArray()); + break; + case KM_TAG_UNLOCKED_DEVICE_REQUIRED: + this.mKeyRequiresUnlockedDevice = getBoolFromAsn1(taggedEntry.getObject()); + break; + default: + break; + } + } + + ASN1Encodable[] hardwareEnforced = ((ASN1Sequence) + keyAttributes.getObjectAt(HW_ENFORCED_INDEX)).toArray(); + for (ASN1Encodable entry : hardwareEnforced) { + ASN1TaggedObject taggedEntry = (ASN1TaggedObject) entry; + switch (taggedEntry.getTagNo()) { + case KM_TAG_NO_AUTH_REQUIRED: + this.mKeyAuthenticatorType = HW_AUTH_NONE; + break; + case KM_TAG_ALL_APPLICATIONS: + this.mKeyAllowedForAllApplications = true; + break; + case KM_TAG_ROOT_OF_TRUST: + ASN1Sequence rootOfTrust = (ASN1Sequence) taggedEntry.getObject(); + this.mVerifiedBootKey = + getOctetsFromAsn1(rootOfTrust.getObjectAt(VERIFIED_BOOT_KEY_INDEX)); + this.mVerifiedBootLocked = + getBoolFromAsn1(rootOfTrust.getObjectAt(VERIFIED_BOOT_LOCKED_INDEX)); + this.mVerifiedBootState = + getVerifiedBootStateEnum( + rootOfTrust.getObjectAt(VERIFIED_BOOT_STATE_INDEX)); + // The verified boot hash was added in structure version 3 (Keymaster 4.0). + if (mAttestationVersion >= 3) { + this.mVerifiedBootHash = + getOctetsFromAsn1( + rootOfTrust.getObjectAt(VERIFIED_BOOT_HASH_INDEX)); + } + break; + case KM_TAG_OS_VERSION: + this.mKeyOsVersion = getIntegerFromAsn1(taggedEntry.getObject()); + break; + case KM_TAG_OS_PATCHLEVEL: + this.mKeyOsPatchLevel = getIntegerFromAsn1(taggedEntry.getObject()); + break; + case KM_TAG_ATTESTATION_ID_BRAND: + this.mDeviceBrand = getUtf8FromOctetsFromAsn1(taggedEntry.getObject()); + break; + case KM_TAG_ATTESTATION_ID_DEVICE: + this.mDeviceName = getUtf8FromOctetsFromAsn1(taggedEntry.getObject()); + break; + case KM_TAG_ATTESTATION_ID_PRODUCT: + this.mDeviceProductName = getUtf8FromOctetsFromAsn1(taggedEntry.getObject()); + break; + case KM_TAG_VENDOR_PATCHLEVEL: + this.mKeyVendorPatchLevel = getIntegerFromAsn1(taggedEntry.getObject()); + break; + case KM_TAG_BOOT_PATCHLEVEL: + this.mKeyBootPatchLevel = getIntegerFromAsn1(taggedEntry.getObject()); + break; + default: + break; + } + } + } + + private void parseAttestationApplicationId(byte [] attestationApplicationId) + throws Exception { + ASN1Sequence outerSequence = ASN1Sequence.getInstance( + new ASN1InputStream(attestationApplicationId).readObject()); + Map<String, Long> packageNameVersion = new HashMap<>(); + ASN1Set packageInfoSet = (ASN1Set) outerSequence.getObjectAt(PACKAGE_INFO_SET_INDEX); + for (ASN1Encodable packageInfoEntry : packageInfoSet.toArray()) { + ASN1Sequence packageInfoSequence = (ASN1Sequence) packageInfoEntry; + packageNameVersion.put( + getUtf8FromOctetsFromAsn1( + packageInfoSequence.getObjectAt(PACKAGE_INFO_NAME_INDEX)), + getLongFromAsn1(packageInfoSequence.getObjectAt(PACKAGE_INFO_VERSION_INDEX))); + } + List<ByteString> certificateDigests = new ArrayList<>(); + ASN1Set certificateDigestSet = + (ASN1Set) outerSequence.getObjectAt(PACKAGE_SIGNATURE_SET_INDEX); + for (ASN1Encodable certificateDigestEntry : certificateDigestSet.toArray()) { + certificateDigests.add(getOctetsFromAsn1(certificateDigestEntry)); + } + this.mApplicationPackageNameVersion = Collections.unmodifiableMap(packageNameVersion); + this.mApplicationCertificateDigests = Collections.unmodifiableList(certificateDigests); + + } + + private VerifiedBootState getVerifiedBootStateEnum(ASN1Encodable asn1) { + int verifiedBoot = getEnumFromAsn1(asn1); + switch (verifiedBoot) { + case KM_VERIFIED_BOOT_STATE_VERIFIED: + return VerifiedBootState.VERIFIED; + case KM_VERIFIED_BOOT_STATE_SELF_SIGNED: + return VerifiedBootState.SELF_SIGNED; + case KM_VERIFIED_BOOT_STATE_UNVERIFIED: + return VerifiedBootState.UNVERIFIED; + case KM_VERIFIED_BOOT_STATE_FAILED: + return VerifiedBootState.FAILED; + default: + throw new IllegalArgumentException("Invalid verified boot state."); + } + } + + private SecurityLevel getSecurityLevelEnum(ASN1Encodable asn1) { + int securityLevel = getEnumFromAsn1(asn1); + switch (securityLevel) { + case KM_SECURITY_LEVEL_SOFTWARE: + return SecurityLevel.SOFTWARE; + case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT: + return SecurityLevel.TRUSTED_ENVIRONMENT; + case KM_SECURITY_LEVEL_STRONG_BOX: + return SecurityLevel.STRONG_BOX; + default: + throw new IllegalArgumentException("Invalid security level."); + } + } + + @NonNull + private ByteString getOctetsFromAsn1(ASN1Encodable asn1) { + return ByteString.copyFrom(((ASN1OctetString) asn1).getOctets()); + } + + @NonNull + private String getUtf8FromOctetsFromAsn1(ASN1Encodable asn1) { + return new String(((ASN1OctetString) asn1).getOctets(), StandardCharsets.UTF_8); + } + + @NonNull + private int getIntegerFromAsn1(ASN1Encodable asn1) { + return ((ASN1Integer) asn1).getValue().intValueExact(); + } + + @NonNull + private long getLongFromAsn1(ASN1Encodable asn1) { + return ((ASN1Integer) asn1).getValue().longValueExact(); + } + + @NonNull + private int getEnumFromAsn1(ASN1Encodable asn1) { + return ((ASN1Enumerated) asn1).getValue().intValueExact(); + } + + @Nullable + private Boolean getBoolFromAsn1(ASN1Encodable asn1) { + if (asn1 instanceof ASN1Boolean) { + return ((ASN1Boolean) asn1).isTrue(); + } + return null; + } +} diff --git a/services/core/java/com/android/server/security/AttestationVerificationManagerService.java b/services/core/java/com/android/server/security/AttestationVerificationManagerService.java index 243efb5e58ce..863f2d1a762d 100644 --- a/services/core/java/com/android/server/security/AttestationVerificationManagerService.java +++ b/services/core/java/com/android/server/security/AttestationVerificationManagerService.java @@ -16,6 +16,7 @@ package com.android.server.security; +import static android.security.attestationverification.AttestationVerificationManager.PROFILE_PEER_DEVICE; import static android.security.attestationverification.AttestationVerificationManager.PROFILE_SELF_TRUSTED; import static android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE; import static android.security.attestationverification.AttestationVerificationManager.RESULT_UNKNOWN; @@ -44,9 +45,11 @@ import com.android.server.SystemService; public class AttestationVerificationManagerService extends SystemService { private static final String TAG = "AVF"; + private final AttestationVerificationPeerDeviceVerifier mPeerDeviceVerifier; - public AttestationVerificationManagerService(final Context context) { + public AttestationVerificationManagerService(final Context context) throws Exception { super(context); + mPeerDeviceVerifier = new AttestationVerificationPeerDeviceVerifier(context); } private final IBinder mService = new IAttestationVerificationManagerService.Stub() { @@ -83,7 +86,7 @@ public class AttestationVerificationManagerService extends SystemService { result.token = null; switch (profile.getAttestationProfileId()) { case PROFILE_SELF_TRUSTED: - Slog.d(TAG, "Verifying Self trusted profile."); + Slog.d(TAG, "Verifying Self Trusted profile."); try { result.resultCode = AttestationVerificationSelfTrustedVerifierForTesting.getInstance() @@ -92,6 +95,11 @@ public class AttestationVerificationManagerService extends SystemService { result.resultCode = RESULT_FAILURE; } break; + case PROFILE_PEER_DEVICE: + Slog.d(TAG, "Verifying Peer Device profile."); + result.resultCode = mPeerDeviceVerifier.verifyAttestation( + localBindingType, requirements, attestation); + break; default: Slog.d(TAG, "No profile found, defaulting."); result.resultCode = RESULT_UNKNOWN; diff --git a/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java b/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java new file mode 100644 index 000000000000..0f8be5a77944 --- /dev/null +++ b/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java @@ -0,0 +1,510 @@ +/* + * 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.security; + +import static android.security.attestationverification.AttestationVerificationManager.PARAM_CHALLENGE; +import static android.security.attestationverification.AttestationVerificationManager.PARAM_PUBLIC_KEY; +import static android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE; +import static android.security.attestationverification.AttestationVerificationManager.RESULT_SUCCESS; +import static android.security.attestationverification.AttestationVerificationManager.TYPE_CHALLENGE; +import static android.security.attestationverification.AttestationVerificationManager.TYPE_PUBLIC_KEY; + +import static com.android.server.security.AndroidKeystoreAttestationVerificationAttributes.VerifiedBootState.VERIFIED; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import android.annotation.NonNull; +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.util.Log; +import android.util.Slog; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; + +import org.json.JSONObject; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.net.URL; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.PKIXCertPathChecker; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509Certificate; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * Verifies Android key attestation according to the {@code PROFILE_PEER_DEVICE} profile. + * + * Trust anchors are vendor-defined via the vendor_required_attestation_certificates.xml resource. + * The profile is satisfied by checking all the following: + * * TrustAnchor match + * * Certificate validity + * * Android OS 10 or higher + * * Hardware backed key store + * * Verified boot locked + * * Remote Patch level must be within 1 year of local patch if local patch is less than 1 year old. + * + */ +class AttestationVerificationPeerDeviceVerifier { + private static final String TAG = "AVF"; + private static final boolean DEBUG = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.VERBOSE); + private static final int MAX_PATCH_AGE_MONTHS = 12; + + private final Context mContext; + private final Set<TrustAnchor> mTrustAnchors; + private final boolean mRevocationEnabled; + private final LocalDate mTestSystemDate; + private final LocalDate mTestLocalPatchDate; + private CertificateFactory mCertificateFactory; + private CertPathValidator mCertPathValidator; + + private static void debugVerboseLog(String str, Throwable t) { + if (DEBUG) { + Slog.v(TAG, str, t); + } + } + + private static void debugVerboseLog(String str) { + if (DEBUG) { + Slog.v(TAG, str); + } + } + + AttestationVerificationPeerDeviceVerifier(@NonNull Context context) throws Exception { + mContext = Objects.requireNonNull(context); + mCertificateFactory = CertificateFactory.getInstance("X.509"); + mCertPathValidator = CertPathValidator.getInstance("PKIX"); + mTrustAnchors = getTrustAnchors(); + mRevocationEnabled = true; + mTestSystemDate = null; + mTestLocalPatchDate = null; + } + + // Use ONLY for hermetic unit testing. + @VisibleForTesting + AttestationVerificationPeerDeviceVerifier(@NonNull Context context, + Set<TrustAnchor> trustAnchors, boolean revocationEnabled, + LocalDate systemDate, LocalDate localPatchDate) throws Exception { + mContext = Objects.requireNonNull(context); + mCertificateFactory = CertificateFactory.getInstance("X.509"); + mCertPathValidator = CertPathValidator.getInstance("PKIX"); + mTrustAnchors = trustAnchors; + mRevocationEnabled = revocationEnabled; + mTestSystemDate = systemDate; + mTestLocalPatchDate = localPatchDate; + } + + /** + * Verifies attestation for public key or challenge local binding. + * + * The attestations must be suitable for {@link java.security.cert.CertificateFactory} + * The certificates in the attestation provided must be DER-encoded and may be supplied in + * binary or printable (Base64) encoding. If the certificate is provided in Base64 encoding, + * it must be bounded at the beginning by -----BEGIN CERTIFICATE-----, and must be bounded at + * the end by -----END CERTIFICATE-----. + * + * @param localBindingType Only {@code TYPE_PUBLIC_KEY} and {@code TYPE_CHALLENGE} supported. + * @param requirements Only {@code PARAM_PUBLIC_KEY} and {@code PARAM_CHALLENGE} supported. + * @param attestation Certificates should be DER encoded with leaf certificate appended first. + */ + int verifyAttestation( + int localBindingType, @NonNull Bundle requirements, @NonNull byte[] attestation) { + int status = RESULT_FAILURE; + + if (mCertificateFactory == null) { + debugVerboseLog("Was unable to initialize CertificateFactory onCreate."); + return status; + } + + if (mCertPathValidator == null) { + debugVerboseLog("Was unable to initialize CertPathValidator onCreate."); + return status; + } + + List<X509Certificate> certificates; + try { + certificates = getCertificates(attestation); + } catch (CertificateException e) { + debugVerboseLog("Unable to parse attestation certificates.", e); + return status; + } + + if (certificates.isEmpty()) { + debugVerboseLog("Attestation contains no certificates."); + return status; + } + + X509Certificate leafNode = certificates.get(0); + if (validateRequirements(localBindingType, requirements) + && validateCertificateChain(certificates) + && checkCertificateAttributes(leafNode, localBindingType, requirements)) { + status = RESULT_SUCCESS; + } else { + status = RESULT_FAILURE; + } + return status; + } + + @NonNull + private List<X509Certificate> getCertificates(byte[] attestation) + throws CertificateException { + List<X509Certificate> certificates = new ArrayList<>(); + ByteArrayInputStream bis = new ByteArrayInputStream(attestation); + while (bis.available() > 0) { + certificates.add((X509Certificate) mCertificateFactory.generateCertificate(bis)); + } + + return certificates; + } + + private boolean validateRequirements(int localBindingType, Bundle requirements) { + if (requirements.size() != 1) { + debugVerboseLog("Requirements does not contain exactly 1 key."); + return false; + } + + if (localBindingType != TYPE_PUBLIC_KEY && localBindingType != TYPE_CHALLENGE) { + debugVerboseLog("Binding type is not supported: " + localBindingType); + return false; + } + + if (localBindingType == TYPE_PUBLIC_KEY && !requirements.containsKey(PARAM_PUBLIC_KEY)) { + debugVerboseLog("Requirements does not contain key: " + PARAM_PUBLIC_KEY); + return false; + } + + if (localBindingType == TYPE_CHALLENGE && !requirements.containsKey(PARAM_CHALLENGE)) { + debugVerboseLog("Requirements does not contain key: " + PARAM_CHALLENGE); + return false; + } + + return true; + } + + private boolean validateCertificateChain(List<X509Certificate> certificates) { + if (certificates.size() < 2) { + debugVerboseLog("Certificate chain less than 2 in size."); + return false; + } + + try { + CertPath certificatePath = mCertificateFactory.generateCertPath(certificates); + PKIXParameters validationParams = new PKIXParameters(mTrustAnchors); + if (mRevocationEnabled) { + // Checks Revocation Status List based on + // https://developer.android.com/training/articles/security-key-attestation#certificate_status + PKIXCertPathChecker checker = new AndroidRevocationStatusListChecker(); + validationParams.addCertPathChecker(checker); + } + // Do not use built-in revocation status checker. + validationParams.setRevocationEnabled(false); + mCertPathValidator.validate(certificatePath, validationParams); + } catch (Throwable t) { + debugVerboseLog("Invalid certificate chain.", t); + return false; + } + return true; + } + + private Set<TrustAnchor> getTrustAnchors() throws CertPathValidatorException { + Set<TrustAnchor> modifiableSet = new HashSet<>(); + try { + for (String certString: getTrustAnchorResources()) { + modifiableSet.add( + new TrustAnchor((X509Certificate) mCertificateFactory.generateCertificate( + new ByteArrayInputStream(getCertificateBytes(certString))), null)); + } + } catch (CertificateException e) { + e.printStackTrace(); + throw new CertPathValidatorException("Invalid trust anchor certificate.", e); + } + return Collections.unmodifiableSet(modifiableSet); + } + + private byte[] getCertificateBytes(String certString) { + String formattedCertString = certString.replaceAll("\\s+", "\n"); + formattedCertString = formattedCertString.replaceAll( + "-BEGIN\\nCERTIFICATE-", "-BEGIN CERTIFICATE-"); + formattedCertString = formattedCertString.replaceAll( + "-END\\nCERTIFICATE-", "-END CERTIFICATE-"); + return formattedCertString.getBytes(UTF_8); + } + + private String[] getTrustAnchorResources() { + return mContext.getResources().getStringArray( + R.array.vendor_required_attestation_certificates); + } + + private boolean checkCertificateAttributes( + X509Certificate leafCertificate, int localBindingType, Bundle requirements) { + AndroidKeystoreAttestationVerificationAttributes attestationAttributes; + try { + attestationAttributes = + AndroidKeystoreAttestationVerificationAttributes.fromCertificate( + leafCertificate); + } catch (Throwable t) { + debugVerboseLog("Could not get ParsedAttestationAttributes from Certificate.", t); + return false; + } + + // Checks for support of Keymaster 4. + if (attestationAttributes.getAttestationVersion() < 3) { + debugVerboseLog("Attestation version is not at least 3 (Keymaster 4)."); + return false; + } + + // Checks for support of Keymaster 4. + if (attestationAttributes.getKeymasterVersion() < 4) { + debugVerboseLog("Keymaster version is not at least 4."); + return false; + } + + // First two characters are Android OS version. + if (attestationAttributes.getKeyOsVersion() < 100000) { + debugVerboseLog("Android OS version is not 10+."); + return false; + } + + if (!attestationAttributes.isAttestationHardwareBacked()) { + debugVerboseLog("Key is not HW backed."); + return false; + } + + if (!attestationAttributes.isKeymasterHardwareBacked()) { + debugVerboseLog("Keymaster is not HW backed."); + return false; + } + + if (attestationAttributes.getVerifiedBootState() != VERIFIED) { + debugVerboseLog("Boot state not Verified."); + return false; + } + + try { + if (!attestationAttributes.isVerifiedBootLocked()) { + debugVerboseLog("Verified boot state is not locked."); + return false; + } + } catch (IllegalStateException e) { + debugVerboseLog("VerifiedBootLocked is not set.", e); + return false; + } + + // Patch level integer YYYYMM is expected to be within 1 year of today. + if (!isValidPatchLevel(attestationAttributes.getKeyOsPatchLevel())) { + debugVerboseLog("OS patch level is not within valid range."); + return false; + } + + // Patch level integer YYYYMMDD is expected to be within 1 year of today. + if (!isValidPatchLevel(attestationAttributes.getKeyBootPatchLevel())) { + debugVerboseLog("Boot patch level is not within valid range."); + return false; + } + + if (!isValidPatchLevel(attestationAttributes.getKeyVendorPatchLevel())) { + debugVerboseLog("Vendor patch level is not within valid range."); + return false; + } + + if (!isValidPatchLevel(attestationAttributes.getKeyBootPatchLevel())) { + debugVerboseLog("Boot patch level is not within valid range."); + return false; + } + + // Verify leaf public key matches provided public key. + if (localBindingType == TYPE_PUBLIC_KEY + && !Arrays.equals(requirements.getByteArray(PARAM_PUBLIC_KEY), + leafCertificate.getPublicKey().getEncoded())) { + debugVerboseLog("Provided public key does not match leaf certificate public key."); + return false; + } + + // Verify challenge matches provided challenge. + if (localBindingType == TYPE_CHALLENGE + && !Arrays.equals(requirements.getByteArray(PARAM_CHALLENGE), + attestationAttributes.getAttestationChallenge().toByteArray())) { + debugVerboseLog("Provided challenge does not match leaf certificate challenge."); + return false; + } + + return true; + } + + /** + * Validates patchLevel passed is within range of the local device patch date if local patch is + * not over one year old. Since the time can be changed on device, just checking the patch date + * is not enough. Therefore, we also confirm the patch level for the remote and local device are + * similar. + */ + private boolean isValidPatchLevel(int patchLevel) { + LocalDate currentDate = mTestSystemDate != null + ? mTestSystemDate : LocalDate.now(ZoneId.systemDefault()); + + // Convert local patch date to LocalDate. + LocalDate localPatchDate; + try { + if (mTestLocalPatchDate != null) { + localPatchDate = mTestLocalPatchDate; + } else { + localPatchDate = LocalDate.parse(Build.VERSION.SECURITY_PATCH); + } + } catch (Throwable t) { + debugVerboseLog("Build.VERSION.SECURITY_PATCH: " + + Build.VERSION.SECURITY_PATCH + " is not in format YYYY-MM-DD"); + return false; + } + + // Check local patch date is not in last year of system clock. + if (ChronoUnit.MONTHS.between(localPatchDate, currentDate) > MAX_PATCH_AGE_MONTHS) { + return true; + } + + // Convert remote patch dates to LocalDate. + String remoteDeviceDateStr = String.valueOf(patchLevel); + if (remoteDeviceDateStr.length() != 6 && remoteDeviceDateStr.length() != 8) { + debugVerboseLog("Patch level is not in format YYYYMM or YYYYMMDD"); + return false; + } + + int patchYear = Integer.parseInt(remoteDeviceDateStr.substring(0, 4)); + int patchMonth = Integer.parseInt(remoteDeviceDateStr.substring(4, 6)); + LocalDate remotePatchDate = LocalDate.of(patchYear, patchMonth, 1); + + // Check patch dates are within 1 year of each other + boolean IsRemotePatchWithinOneYearOfLocalPatch; + if (remotePatchDate.compareTo(localPatchDate) > 0) { + IsRemotePatchWithinOneYearOfLocalPatch = ChronoUnit.MONTHS.between( + localPatchDate, remotePatchDate) <= MAX_PATCH_AGE_MONTHS; + } else if (remotePatchDate.compareTo(localPatchDate) < 0) { + IsRemotePatchWithinOneYearOfLocalPatch = ChronoUnit.MONTHS.between( + remotePatchDate, localPatchDate) <= MAX_PATCH_AGE_MONTHS; + } else { + IsRemotePatchWithinOneYearOfLocalPatch = true; + } + + return IsRemotePatchWithinOneYearOfLocalPatch; + } + + /** + * Checks certificate revocation status. + * + * Queries status list from android.googleapis.com/attestation/status and checks for + * the existence of certificate's serial number. If serial number exists in map, then fail. + */ + private final class AndroidRevocationStatusListChecker extends PKIXCertPathChecker { + private static final String TOP_LEVEL_JSON_PROPERTY_KEY = "entries"; + private static final String STATUS_PROPERTY_KEY = "status"; + private static final String REASON_PROPERTY_KEY = "reason"; + private String mStatusUrl; + private JSONObject mJsonStatusMap; + + @Override + public void init(boolean forward) throws CertPathValidatorException { + mStatusUrl = getRevocationListUrl(); + if (mStatusUrl == null || mStatusUrl.isEmpty()) { + throw new CertPathValidatorException( + "R.string.vendor_required_attestation_revocation_list_url is empty."); + } + // TODO(b/221067843): Update to only pull status map on non critical path and if + // out of date (24hrs). + mJsonStatusMap = getStatusMap(mStatusUrl); + } + + @Override + public boolean isForwardCheckingSupported() { + return false; + } + + @Override + public Set<String> getSupportedExtensions() { + return null; + } + + @Override + public void check(Certificate cert, Collection<String> unresolvedCritExts) + throws CertPathValidatorException { + X509Certificate x509Certificate = (X509Certificate) cert; + // The json key is the certificate's serial number converted to lowercase hex. + String serialNumber = x509Certificate.getSerialNumber().toString(16); + + if (serialNumber == null) { + throw new CertPathValidatorException("Certificate serial number can not be null."); + } + + if (mJsonStatusMap.has(serialNumber)) { + JSONObject revocationStatus; + String status; + String reason; + try { + revocationStatus = mJsonStatusMap.getJSONObject(serialNumber); + status = revocationStatus.getString(STATUS_PROPERTY_KEY); + reason = revocationStatus.getString(REASON_PROPERTY_KEY); + } catch (Throwable t) { + throw new CertPathValidatorException("Unable get properties for certificate " + + "with serial number " + serialNumber); + } + throw new CertPathValidatorException( + "Invalid certificate with serial number " + serialNumber + + " has status " + status + + " because reason " + reason); + } + } + + private JSONObject getStatusMap(String stringUrl) throws CertPathValidatorException { + URL url; + try { + url = new URL(stringUrl); + } catch (Throwable t) { + throw new CertPathValidatorException( + "Unable to get revocation status from " + mStatusUrl, t); + } + + try (InputStream inputStream = url.openStream()) { + JSONObject statusListJson = new JSONObject( + new String(inputStream.readAllBytes(), UTF_8)); + return statusListJson.getJSONObject(TOP_LEVEL_JSON_PROPERTY_KEY); + } catch (Throwable t) { + throw new CertPathValidatorException( + "Unable to parse revocation status from " + mStatusUrl, t); + } + } + + private String getRevocationListUrl() { + return mContext.getResources().getString( + R.string.vendor_required_attestation_revocation_list_url); + } + } +} diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java index fa243c023a87..20cd8f5c12f8 100644 --- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java +++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java @@ -671,6 +671,7 @@ public class TrustAgentWrapper { mContext.unbindService(mConnection); mBound = false; mContext.unregisterReceiver(mBroadcastReceiver); + mContext.unregisterReceiver(mTrustableDowngradeReceiver); mTrustAgentService = null; mSetTrustAgentFeaturesToken = null; mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java index 6c5d9520151b..aad59c67b60c 100644 --- a/services/core/java/com/android/server/vibrator/VibrationSettings.java +++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java @@ -347,24 +347,19 @@ final class VibrationSettings { * Return {@code true} if the device should vibrate for current ringer mode. * * <p>This checks the current {@link AudioManager#getRingerModeInternal()} against user settings - * for touch and ringtone usages only. All other usages are allowed by this method. + * for ringtone usage only. All other usages are allowed by this method. */ @GuardedBy("mLock") private boolean shouldVibrateForRingerModeLocked(@VibrationAttributes.Usage int usageHint) { + if (usageHint != USAGE_RINGTONE) { + // Only ringtone vibrations are disabled when phone is on silent mode. + return true; + } // If audio manager was not loaded yet then assume most restrictive mode. int ringerMode = (mAudioManager == null) ? AudioManager.RINGER_MODE_SILENT : mAudioManager.getRingerModeInternal(); - - switch (usageHint) { - case USAGE_TOUCH: - case USAGE_RINGTONE: - // Touch feedback and ringtone disabled when phone is on silent mode. - return ringerMode != AudioManager.RINGER_MODE_SILENT; - default: - // All other usages ignore ringer mode settings. - return true; - } + return ringerMode != AudioManager.RINGER_MODE_SILENT; } /** Updates all vibration settings and triggers registered listeners. */ diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java index 366763110565..024e319233f8 100644 --- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java +++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java @@ -16,6 +16,7 @@ package com.android.server.vibrator; +import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Build; import android.os.CombinedVibration; @@ -24,6 +25,7 @@ import android.os.vibrator.PrebakedSegment; import android.os.vibrator.PrimitiveSegment; import android.os.vibrator.RampSegment; import android.os.vibrator.VibrationEffectSegment; +import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; @@ -69,9 +71,17 @@ final class VibrationStepConductor { private final PriorityQueue<Step> mNextSteps = new PriorityQueue<>(); private final Queue<Step> mPendingOnVibratorCompleteSteps = new LinkedList<>(); + + // Signalling fields. + @GuardedBy("mLock") + private final IntArray mSignalVibratorsComplete; + @GuardedBy("mLock") + private boolean mSignalCancel = false; @GuardedBy("mLock") - private Queue<Integer> mCompletionNotifiedVibrators = new LinkedList<>(); + private boolean mSignalCancelImmediate = false; + private boolean mCancelled = false; + private boolean mCancelledImmediately = false; // hard stop private int mPendingVibrateSteps; private int mRemainingStartSequentialEffectSteps; private int mSuccessfulVibratorOnSteps; @@ -91,6 +101,7 @@ final class VibrationStepConductor { mVibrators.put(availableVibrators.keyAt(i), availableVibrators.valueAt(i)); } } + this.mSignalVibratorsComplete = new IntArray(mVibrators.size()); } @Nullable @@ -152,6 +163,10 @@ final class VibrationStepConductor { if (Build.IS_DEBUGGABLE) { expectIsVibrationThread(true); } + if (mCancelledImmediately) { + return true; // Terminate. + } + // No need to check for vibration complete callbacks - if there were any, they would // have no steps to notify anyway. return mPendingOnVibratorCompleteSteps.isEmpty() && mNextSteps.isEmpty(); @@ -166,6 +181,9 @@ final class VibrationStepConductor { expectIsVibrationThread(true); } + if (mCancelled) { + return Vibration.Status.CANCELLED; + } if (mPendingVibrateSteps > 0 || mRemainingStartSequentialEffectSteps > 0) { return Vibration.Status.RUNNING; @@ -180,50 +198,67 @@ final class VibrationStepConductor { /** * Blocks until the next step is due to run. The wait here may be interrupted by calling - * {@link #notifyWakeUp} or other "notify" methods. + * one of the "notify" methods. * - * <p>This method returns false if the next step is ready to run now. If the method returns - * true, then some waiting was done, but may have been interrupted by a wakeUp. + * <p>This method returns true if the next step is ready to run now. If the method returns + * false, then some waiting was done, but may have been interrupted by a wakeUp, and the + * status and isFinished of the vibration should be re-checked before calling this method again. * - * @return true if the method waited at all, or false if a step is ready to run now. + * @return true if the next step can be run now or the vibration is finished, or false if this + * method waited and the conductor state may have changed asynchronously, in which case this + * method needs to be run again. */ public boolean waitUntilNextStepIsDue() { if (Build.IS_DEBUGGABLE) { expectIsVibrationThread(true); } - // It's necessary to re-process callbacks if they come in after acquiring the lock to - // start waiting, but we don't want to hold the lock while processing them. - // The loop goes until there are no pending callbacks to process. - while (true) { - // TODO: cancellation checking could also be integrated here, instead of outside in - // VibrationThread. - processVibratorCompleteCallbacks(); - if (!mPendingOnVibratorCompleteSteps.isEmpty()) { - // Steps resumed by vibrator complete callback should be played right away. - return false; - } - Step nextStep = mNextSteps.peek(); - if (nextStep == null) { - return false; - } - long waitMillis = nextStep.calculateWaitTime(); - if (waitMillis <= 0) { + + processAllNotifySignals(); + if (mCancelledImmediately) { + // Don't try to run a step for immediate cancel, although there should be none left. + // Non-immediate cancellation may have cleanup steps, so it continues processing. + return false; + } + if (!mPendingOnVibratorCompleteSteps.isEmpty()) { + return true; // Resumed step ready. + } + Step nextStep = mNextSteps.peek(); + if (nextStep == null) { + return true; // Finished + } + long waitMillis = nextStep.calculateWaitTime(); + if (waitMillis <= 0) { + return true; // Regular step ready + } + synchronized (mLock) { + // Double check for signals before sleeping, as their notify wouldn't interrupt a fresh + // wait. + if (hasPendingNotifySignalLocked()) { + // Don't run the next step, it will loop back to this method and process them. return false; } - synchronized (mLock) { - // Double check for missed wake-ups before sleeping. - if (!mCompletionNotifiedVibrators.isEmpty()) { - continue; // Start again: processVibratorCompleteCallbacks will consume it. - } - try { - mLock.wait(waitMillis); - } catch (InterruptedException e) { - } - return true; + try { + mLock.wait(waitMillis); + } catch (InterruptedException e) { } + return false; // Caller needs to check isFinished and maybe wait again. } } + @Nullable + private Step pollNext() { + if (Build.IS_DEBUGGABLE) { + expectIsVibrationThread(true); + } + + // Prioritize the steps resumed by a vibrator complete callback, irrespective of their + // "next run time". + if (!mPendingOnVibratorCompleteSteps.isEmpty()) { + return mPendingOnVibratorCompleteSteps.poll(); + } + return mNextSteps.poll(); + } + /** * Play and remove the step at the top of this queue, and also adds the next steps generated * to be played next. @@ -255,20 +290,27 @@ final class VibrationStepConductor { } /** - * Wake up the execution thread, which may be waiting until the next step is due. - * The caller is responsible for diverting VibrationThread execution. + * Notify the execution that cancellation is requested. This will be acted upon + * asynchronously in the VibrationThread. * - * <p>At the moment this is used after the signal is set that a cancellation needs to be - * processed. The actual cancellation will be invoked from the VibrationThread. + * @param immediate indicates whether cancellation should abort urgently and skip cleanup steps. */ - public void notifyWakeUp() { + public void notifyCancelled(boolean immediate) { if (Build.IS_DEBUGGABLE) { expectIsVibrationThread(false); } - synchronized (mLock) { + if (immediate && mSignalCancelImmediate || mSignalCancel) { + // Nothing to update: already cancelled previously. + return; + } + mSignalCancelImmediate |= immediate; + mSignalCancel = true; mLock.notify(); } + if (DEBUG) { + Slog.d(TAG, "Vibration cancel requested, immediate=" + immediate); + } } /** @@ -287,7 +329,7 @@ final class VibrationStepConductor { } synchronized (mLock) { - mCompletionNotifiedVibrators.offer(vibratorId); + mSignalVibratorsComplete.add(vibratorId); mLock.notify(); } } @@ -310,23 +352,80 @@ final class VibrationStepConductor { synchronized (mLock) { for (int i = 0; i < mVibrators.size(); i++) { - mCompletionNotifiedVibrators.offer(mVibrators.keyAt(i)); + mSignalVibratorsComplete.add(mVibrators.keyAt(i)); } mLock.notify(); } } + @GuardedBy("mLock") + private boolean hasPendingNotifySignalLocked() { + if (Build.IS_DEBUGGABLE) { + expectIsVibrationThread(true); // Reads VibrationThread variables as well as signals. + } + return (mSignalCancel && !mCancelled) + || (mSignalCancelImmediate && !mCancelledImmediately) + || (mSignalVibratorsComplete.size() > 0); + } + + /** + * Process any notified cross-thread signals, applying the necessary VibrationThread state + * changes. + */ + private void processAllNotifySignals() { + if (Build.IS_DEBUGGABLE) { + expectIsVibrationThread(true); + } + + int[] vibratorsToProcess = null; + boolean doCancel = false; + boolean doCancelImmediate = false; + // Swap out the queue of completions to process. + synchronized (mLock) { + if (mSignalCancelImmediate) { + if (mCancelledImmediately) { + Slog.wtf(TAG, "Immediate cancellation signal processed twice"); + } + // This should only happen once. + doCancelImmediate = true; + } + if (mSignalCancel && !mCancelled) { + doCancel = true; + } + if (!doCancelImmediate && mSignalVibratorsComplete.size() > 0) { + vibratorsToProcess = mSignalVibratorsComplete.toArray(); // makes a copy + mSignalVibratorsComplete.clear(); + } + } + + // Force cancellation means stop everything and clear all steps, so the execution loop + // shouldn't come back to this method. To observe explicitly: this drops vibrator + // completion signals that were collected in this call, but we won't process them + // anyway as all steps are cancelled. + if (doCancelImmediate) { + processCancelImmediately(); + return; + } + if (doCancel) { + processCancel(); + } + if (vibratorsToProcess != null) { + processVibratorsComplete(vibratorsToProcess); + } + } + /** * Cancel the current queue, replacing all remaining steps with respective clean-up steps. * - * <p>This will remove all steps and replace them with respective + * <p>This will remove all steps and replace them with respective results of * {@link Step#cancel()}. */ - public void cancel() { + public void processCancel() { if (Build.IS_DEBUGGABLE) { expectIsVibrationThread(true); } + mCancelled = true; // Vibrator callbacks should wait until all steps from the queue are properly cancelled // and clean up steps are added back to the queue, so they can handle the callback. List<Step> cleanUpSteps = new ArrayList<>(); @@ -344,11 +443,13 @@ final class VibrationStepConductor { * * <p>This will remove and trigger {@link Step#cancelImmediately()} in all steps, in order. */ - public void cancelImmediately() { + public void processCancelImmediately() { if (Build.IS_DEBUGGABLE) { expectIsVibrationThread(true); } + mCancelledImmediately = true; + mCancelled = true; Step step; while ((step = pollNext()) != null) { step.cancelImmediately(); @@ -356,44 +457,20 @@ final class VibrationStepConductor { mPendingVibrateSteps = 0; } - @Nullable - private Step pollNext() { - if (Build.IS_DEBUGGABLE) { - expectIsVibrationThread(true); - } - - // Prioritize the steps resumed by a vibrator complete callback, irrespective of their - // "next run time". - if (!mPendingOnVibratorCompleteSteps.isEmpty()) { - return mPendingOnVibratorCompleteSteps.poll(); - } - return mNextSteps.poll(); - } - /** - * Process any notified vibrator completions. + * Processes the vibrators that have sent their complete callbacks. A step is found that will + * accept the completion callback, and this step is brought forward for execution in the next + * run. * * <p>This assumes only one of the next steps is waiting on this given vibrator, so the * first step found will be resumed by this method, in no particular order. */ - private void processVibratorCompleteCallbacks() { + private void processVibratorsComplete(@NonNull int[] vibratorsToProcess) { if (Build.IS_DEBUGGABLE) { expectIsVibrationThread(true); } - Queue<Integer> vibratorsToProcess; - // Swap out the queue of completions to process. - synchronized (mLock) { - if (mCompletionNotifiedVibrators.isEmpty()) { - return; // Nothing to do. - } - - vibratorsToProcess = mCompletionNotifiedVibrators; - mCompletionNotifiedVibrators = new LinkedList<>(); - } - - while (!vibratorsToProcess.isEmpty()) { - int vibratorId = vibratorsToProcess.poll(); + for (int vibratorId : vibratorsToProcess) { Iterator<Step> it = mNextSteps.iterator(); while (it.hasNext()) { Step step = it.next(); diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java index 3fef7f2a747e..26f7e7dee757 100644 --- a/services/core/java/com/android/server/vibrator/VibrationThread.java +++ b/services/core/java/com/android/server/vibrator/VibrationThread.java @@ -108,7 +108,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient { if (DEBUG) { Slog.d(TAG, "Binder died, cancelling vibration..."); } - cancel(); + mStepConductor.notifyCancelled(/* immediate= */ false); } @Override @@ -168,28 +168,12 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient { /** Cancel current vibration and ramp down the vibrators gracefully. */ public void cancel() { - if (mStop) { - // Already cancelled, running clean-up steps. - return; - } - mStop = true; - if (DEBUG) { - Slog.d(TAG, "Vibration cancelled"); - } - mStepConductor.notifyWakeUp(); + mStepConductor.notifyCancelled(/* immediate= */ false); } /** Cancel current vibration and shuts off the vibrators immediately. */ public void cancelImmediately() { - if (mForceStop) { - // Already forced the thread to stop, wait for it to finish. - return; - } - if (DEBUG) { - Slog.d(TAG, "Vibration cancelled immediately"); - } - mStop = mForceStop = true; - mStepConductor.notifyWakeUp(); + mStepConductor.notifyCancelled(/* immediate= */ true); } /** Notify current vibration that a synced step has completed. */ @@ -217,13 +201,10 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playVibration"); try { mStepConductor.prepareToStart(); - while (!mStepConductor.isFinished()) { - // Skip wait and next step if mForceStop already happened. - boolean waited = mForceStop || mStepConductor.waitUntilNextStepIsDue(); - // If we waited, don't run the next step, but instead re-evaluate cancellation - // status - if (!waited) { + boolean readyToRun = mStepConductor.waitUntilNextStepIsDue(); + // If we waited, don't run the next step, but instead re-evaluate status. + if (readyToRun) { if (DEBUG) { Slog.d(TAG, "Play vibration consuming next step..."); } @@ -232,23 +213,12 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient { mStepConductor.runNextStep(); } - if (mForceStop) { - // Cancel every step and stop playing them right away, even clean-up steps. - mStepConductor.cancelImmediately(); - clientVibrationCompleteIfNotAlready(Vibration.Status.CANCELLED); - break; - } - - Vibration.Status status = mStop ? Vibration.Status.CANCELLED - : mStepConductor.calculateVibrationStatus(); + Vibration.Status status = mStepConductor.calculateVibrationStatus(); // This block can only run once due to mCalledVibrationCompleteCallback. if (status != Vibration.Status.RUNNING && !mCalledVibrationCompleteCallback) { // First time vibration stopped running, start clean-up tasks and notify // callback immediately. clientVibrationCompleteIfNotAlready(status); - if (status == Vibration.Status.CANCELLED) { - mStepConductor.cancel(); - } } } } finally { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 287248f311a8..26815b4c4fde 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -5084,10 +5084,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } if (!visible) { - final InsetsControlTarget imeInputTarget = mDisplayContent.getImeTarget( - DisplayContent.IME_TARGET_INPUT); - mLastImeShown = imeInputTarget != null && imeInputTarget.getWindow() != null - && imeInputTarget.getWindow().mActivityRecord == this + final InputTarget imeInputTarget = mDisplayContent.getImeInputTarget(); + mLastImeShown = imeInputTarget != null && imeInputTarget.getWindowState() != null + && imeInputTarget.getWindowState().mActivityRecord == this && mDisplayContent.mInputMethodWindow != null && mDisplayContent.mInputMethodWindow.isVisible(); mImeInsetsFrozenUntilStartInput = true; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index e2e42a10cd2d..71a1b3e6c5d2 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -592,7 +592,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * The window which receives input from the input method. This is also a candidate of the * input method control target. */ - private WindowState mImeInputTarget; + private InputTarget mImeInputTarget; + + /** + * The last ime input target processed from setImeLayeringTargetInner + * this is to ensure we update the control target in the case when the IME + * target changes while the IME layering target stays the same, for example + * the case of the IME moving to a SurfaceControlViewHost backed EmbeddedWindow + */ + private InputTarget mLastImeInputTarget; /** * This controls the visibility and animation of the input method window. @@ -608,14 +616,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp static final int IME_TARGET_LAYERING = 0; /** - * Used by {@link #getImeTarget} to return the IME target which received the input connection - * from IME. - * - * @see #mImeInputTarget - */ - static final int IME_TARGET_INPUT = 1; - - /** * Used by {@link #getImeTarget} to return the IME target which controls the IME insets * visibility and animation. * @@ -625,7 +625,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @IntDef(flag = false, prefix = { "IME_TARGET_" }, value = { IME_TARGET_LAYERING, - IME_TARGET_INPUT, IME_TARGET_CONTROL, }) @Retention(RetentionPolicy.SOURCE) @@ -3315,7 +3314,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mImeLayeringTarget.dumpDebug(proto, INPUT_METHOD_TARGET, logLevel); } if (mImeInputTarget != null) { - mImeInputTarget.dumpDebug(proto, INPUT_METHOD_INPUT_TARGET, logLevel); + mImeInputTarget.dumpProto(proto, INPUT_METHOD_INPUT_TARGET, logLevel); } if (mImeControlTarget != null && mImeControlTarget.getWindow() != null) { @@ -3878,7 +3877,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } private boolean isImeControlledByApp() { - return mImeInputTarget != null && !mImeInputTarget.inMultiWindowMode(); + return mImeInputTarget != null && mImeInputTarget.shouldControlIme(); } boolean shouldImeAttachedToApp() { @@ -3941,19 +3940,21 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * * @param type The type of the IME target. * @see #IME_TARGET_LAYERING - * @see #IME_TARGET_INPUT * @see #IME_TARGET_CONTROL */ InsetsControlTarget getImeTarget(@InputMethodTarget int type) { switch (type) { case IME_TARGET_LAYERING: return mImeLayeringTarget; - case IME_TARGET_INPUT: return mImeInputTarget; case IME_TARGET_CONTROL: return mImeControlTarget; default: return null; } } + InputTarget getImeInputTarget() { + return mImeInputTarget; + } + // IMPORTANT: When introducing new dependencies in this method, make sure that // changes to those result in RootWindowContainer.updateDisplayImePolicyCache() // being called. @@ -4002,9 +4003,18 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * placed at its parent's surface. */ private void setImeLayeringTargetInner(@Nullable WindowState target) { - if (target == mImeLayeringTarget) { + /** + * This function is also responsible for updating the IME control target + * and so in the case where the IME layering target does not change + * but the Input target does (for example, IME moving to a SurfaceControlViewHost + * we have to continue executing this function, otherwise there is no work + * to do. + */ + if (target == mImeLayeringTarget && mLastImeInputTarget == mImeInputTarget) { return; } + mLastImeInputTarget = mImeInputTarget; + // If the IME target is the input target, before it changes, prepare the IME screenshot // for the last IME target when its task is applying app transition. This is for the // better IME transition to keep IME visibility when transitioning to the next task. @@ -4046,9 +4056,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } @VisibleForTesting - void setImeInputTarget(WindowState target) { + void setImeInputTarget(InputTarget target) { mImeInputTarget = target; - boolean canScreenshot = mImeInputTarget == null || !mImeInputTarget.isSecureLocked(); + boolean canScreenshot = mImeInputTarget == null || mImeInputTarget.canScreenshotIme(); if (mImeWindowsContainer.setCanScreenshot(canScreenshot)) { mWmService.requestTraversal(); } @@ -4164,7 +4174,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * The IME input target is the window which receives input from IME. It is also a candidate * which controls the visibility and animation of the input method window. */ - void updateImeInputAndControlTarget(WindowState target) { + void updateImeInputAndControlTarget(InputTarget target) { if (mImeInputTarget != target) { ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target); setImeInputTarget(target); @@ -4174,8 +4184,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } // Unfreeze IME insets after the new target updated, in case updateAboveInsetsState may // deliver unrelated IME insets change to the non-IME requester. - if (target != null && target.mActivityRecord != null) { - target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false; + if (target != null) { + target.unfreezeInsetsAfterStartInput(); } } @@ -4233,11 +4243,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp InsetsControlTarget computeImeControlTarget() { if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null || (mImeInputTarget != null - && getImeHostOrFallback(mImeInputTarget.getWindow()) - == mRemoteInsetsControlTarget)) { + && getImeHostOrFallback(mImeInputTarget.getWindowState()) + == mRemoteInsetsControlTarget)) { return mRemoteInsetsControlTarget; } else { - return mImeInputTarget; + return mImeInputTarget != null ? mImeInputTarget.getWindowState() : null; } } @@ -4250,7 +4260,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // screen. If it's not covering the entire screen the IME might extend beyond the apps // bounds. if (shouldImeAttachedToApp()) { - if (mImeLayeringTarget.mActivityRecord != mImeInputTarget.mActivityRecord) { + if (mImeLayeringTarget.mActivityRecord != mImeInputTarget.getActivityRecord()) { // Do not change parent if the window hasn't requested IME. return null; } diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java index 2ab08e6da478..dcc16ebd88f5 100644 --- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java +++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java @@ -17,6 +17,9 @@ package com.android.server.wm; +import static com.android.server.wm.IdentifierProto.HASH_CODE; +import static com.android.server.wm.IdentifierProto.TITLE; +import static com.android.server.wm.WindowContainerProto.IDENTIFIER; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -25,6 +28,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.util.ArrayMap; +import android.util.proto.ProtoOutputStream; import android.util.Slog; import android.view.IWindow; import android.view.InputApplicationHandle; @@ -43,6 +47,8 @@ class EmbeddedWindowController { private ArrayMap<IBinder /*input token */, EmbeddedWindow> mWindows = new ArrayMap<>(); private ArrayMap<IBinder /*focus grant token */, EmbeddedWindow> mWindowsByFocusToken = new ArrayMap<>(); + private ArrayMap<IBinder /*window token*/, EmbeddedWindow> mWindowsByWindowToken = + new ArrayMap<>(); private final Object mGlobalLock; private final ActivityTaskManagerService mAtmService; @@ -63,6 +69,7 @@ class EmbeddedWindowController { mWindows.put(inputToken, window); final IBinder focusToken = window.getFocusGrantToken(); mWindowsByFocusToken.put(focusToken, window); + mWindowsByWindowToken.put(window.getWindowToken(), window); updateProcessController(window); window.mClient.asBinder().linkToDeath(()-> { synchronized (mGlobalLock) { @@ -116,6 +123,7 @@ class EmbeddedWindowController { if (ew.mClient.asBinder() == client.asBinder()) { mWindows.removeAt(i).onRemoved(); mWindowsByFocusToken.remove(ew.getFocusGrantToken()); + mWindowsByWindowToken.remove(ew.getWindowToken()); return; } } @@ -127,6 +135,7 @@ class EmbeddedWindowController { if (ew.mHostWindowState == host) { mWindows.removeAt(i).onRemoved(); mWindowsByFocusToken.remove(ew.getFocusGrantToken()); + mWindowsByWindowToken.remove(ew.getWindowToken()); } } } @@ -139,6 +148,10 @@ class EmbeddedWindowController { return mWindowsByFocusToken.get(focusGrantToken); } + EmbeddedWindow getByWindowToken(IBinder windowToken) { + return mWindowsByWindowToken.get(windowToken); + } + void onActivityRemoved(ActivityRecord activityRecord) { for (int i = mWindows.size() - 1; i >= 0; i--) { final EmbeddedWindow window = mWindows.valueAt(i); @@ -244,15 +257,29 @@ class EmbeddedWindowController { } @Override + public DisplayContent getDisplayContent() { + return mWmService.mRoot.getDisplayContent(getDisplayId()); + } + + @Override public IWindow getIWindow() { return mClient; } + public IBinder getWindowToken() { + return mClient.asBinder(); + } + @Override public int getPid() { return mOwnerPid; } + @Override + public int getUid() { + return mOwnerUid; + } + void setIsOverlay() { mIsOverlay = true; } @@ -297,5 +324,46 @@ class EmbeddedWindowController { public void handleTapOutsideFocusInsideSelf() { handleTap(true); } + + @Override + public boolean shouldControlIme() { + return false; + } + + @Override + public boolean canScreenshotIme() { + return true; + } + + @Override + public void unfreezeInsetsAfterStartInput() { + } + + @Override + public InsetsControlTarget getImeControlTarget() { + return mWmService.getDefaultDisplayContentLocked().mRemoteInsetsControlTarget; + } + + @Override + public boolean isInputMethodClientFocus(int uid, int pid) { + return uid == mOwnerUid && pid == mOwnerPid; + } + + @Override + public ActivityRecord getActivityRecord() { + return null; + } + + @Override + public void dumpProto(ProtoOutputStream proto, long fieldId, + @WindowTraceLogLevel int logLevel) { + final long token = proto.start(fieldId); + + final long token2 = proto.start(IDENTIFIER); + proto.write(HASH_CODE, System.identityHashCode(this)); + proto.write(TITLE, "EmbeddedWindow"); + proto.end(token2); + proto.end(token); + } } } diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index f24e429ca09c..199517c441ad 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -21,7 +21,6 @@ import static android.view.InsetsState.ITYPE_IME; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL; -import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT; import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.ImeInsetsSourceProviderProto.IME_TARGET_FROM_IME; import static com.android.server.wm.ImeInsetsSourceProviderProto.INSETS_SOURCE_PROVIDER; @@ -249,7 +248,7 @@ final class ImeInsetsSourceProvider extends WindowContainerInsetsSourceProvider } private boolean isImeInputTarget(InsetsControlTarget target) { - return target == mDisplayContent.getImeTarget(IME_TARGET_INPUT); + return target == mDisplayContent.getImeInputTarget(); } private boolean sameAsImeControlTarget() { diff --git a/services/core/java/com/android/server/wm/InputTarget.java b/services/core/java/com/android/server/wm/InputTarget.java index 5166b8adcecc..b5ab62b6e03f 100644 --- a/services/core/java/com/android/server/wm/InputTarget.java +++ b/services/core/java/com/android/server/wm/InputTarget.java @@ -17,6 +17,7 @@ package com.android.server.wm; import android.view.IWindow; +import android.util.proto.ProtoOutputStream; /** * Common interface between focusable objects. @@ -36,6 +37,7 @@ interface InputTarget { /* Owning pid of the target. */ int getPid(); + int getUid(); /** * Indicates whether a target should receive focus from server side @@ -45,7 +47,25 @@ interface InputTarget { */ boolean receiveFocusFromTapOutside(); + // Gaining focus void handleTapOutsideFocusInsideSelf(); + // Losing focus void handleTapOutsideFocusOutsideSelf(); + + // Whether this input target can control the IME itself + boolean shouldControlIme(); + // Whether this input target can be screenshoted by the IME system + boolean canScreenshotIme(); + + ActivityRecord getActivityRecord(); + void unfreezeInsetsAfterStartInput(); + + boolean isInputMethodClientFocus(int uid, int pid); + + DisplayContent getDisplayContent(); + InsetsControlTarget getImeControlTarget(); + + void dumpProto(ProtoOutputStream proto, long fieldId, + @WindowTraceLogLevel int logLevel); } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index cc03c60aa6d6..f3933c5f7bd6 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3292,7 +3292,7 @@ class Task extends TaskFragment { // We intend to let organizer manage task visibility but it doesn't // have enough information until we finish shell transitions. // In the mean time we do an easy fix here. - final boolean show = isVisible() || isAnimating(TRANSITION | PARENTS); + final boolean show = isVisible() || isAnimating(TRANSITION | PARENTS | CHILDREN); if (mSurfaceControl != null) { if (show != mLastSurfaceShowing) { getSyncTransaction().setVisibility(mSurfaceControl, show); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index a67f92332d8e..d306082c3e29 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -1023,7 +1023,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return mProvidedInsetsSources; } - DisplayContent getDisplayContent() { + public DisplayContent getDisplayContent() { return mDisplayContent; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 5db72ee722d7..6445d1e657da 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -114,7 +114,6 @@ import static com.android.server.LockGuard.installLock; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY; import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL; -import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT; import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; @@ -5069,6 +5068,15 @@ public class WindowManagerService extends IWindowManager.Stub return null; } + @Nullable InputTarget getInputTargetFromWindowTokenLocked(IBinder windowToken) { + InputTarget window = mWindowMap.get(windowToken); + if (window != null) { + return window; + } + window = mEmbeddedWindowController.getByWindowToken(windowToken); + return window; + } + void reportFocusChanged(IBinder oldToken, IBinder newToken) { InputTarget lastTarget; InputTarget newTarget; @@ -6506,7 +6514,7 @@ public class WindowManagerService extends IWindowManager.Stub mRoot.forAllDisplays(dc -> { final int displayId = dc.getDisplayId(); final InsetsControlTarget imeLayeringTarget = dc.getImeTarget(IME_TARGET_LAYERING); - final InsetsControlTarget imeInputTarget = dc.getImeTarget(IME_TARGET_INPUT); + final InputTarget imeInputTarget = dc.getImeInputTarget(); final InsetsControlTarget imeControlTarget = dc.getImeTarget(IME_TARGET_CONTROL); if (imeLayeringTarget != null) { pw.print(" imeLayeringTarget in display# "); pw.print(displayId); @@ -7714,7 +7722,8 @@ public class WindowManagerService extends IWindowManager.Stub + " imeTargetWindowToken=" + imeTargetWindowToken); } synchronized (mGlobalLock) { - final WindowState imeTarget = mWindowMap.get(imeTargetWindowToken); + InputTarget imeTarget = + getInputTargetFromWindowTokenLocked(imeTargetWindowToken); if (imeTarget != null) { imeTarget.getDisplayContent().updateImeInputAndControlTarget(imeTarget); } @@ -7794,11 +7803,11 @@ public class WindowManagerService extends IWindowManager.Stub } synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getTopFocusedDisplayContent(); - final WindowState window = mWindowMap.get(windowToken); - if (window == null) { + InputTarget target = getInputTargetFromWindowTokenLocked(windowToken); + if (target == null) { return ImeClientFocusResult.NOT_IME_TARGET_WINDOW; } - final int tokenDisplayId = window.getDisplayContent().getDisplayId(); + final int tokenDisplayId = target.getDisplayContent().getDisplayId(); if (tokenDisplayId != displayId) { Slog.e(TAG, "isInputMethodClientFocus: display ID mismatch." + " from client: " + displayId @@ -7811,7 +7820,7 @@ public class WindowManagerService extends IWindowManager.Stub return ImeClientFocusResult.INVALID_DISPLAY_ID; } - if (displayContent.isInputMethodClientFocus(uid, pid)) { + if (target.isInputMethodClientFocus(uid, pid)) { return ImeClientFocusResult.HAS_IME_FOCUS; } // Okay, how about this... what is the current focus? @@ -7835,7 +7844,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void showImePostLayout(IBinder imeTargetWindowToken) { synchronized (mGlobalLock) { - WindowState imeTarget = mWindowMap.get(imeTargetWindowToken); + InputTarget imeTarget = getInputTargetFromWindowTokenLocked(imeTargetWindowToken); if (imeTarget == null) { return; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 26acf43cf9ed..517837c3732a 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -120,7 +120,6 @@ import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE; import static com.android.server.wm.AnimationSpecProto.MOVE; -import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT; import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.DisplayContent.logsGestureExclusionRestrictions; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; @@ -1602,14 +1601,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } @Override - DisplayContent getDisplayContent() { + public DisplayContent getDisplayContent() { return mToken.getDisplayContent(); } @Override void onDisplayChanged(DisplayContent dc) { if (dc != null && mDisplayContent != null && dc != mDisplayContent - && getImeInputTarget() == this) { + && mDisplayContent.getImeInputTarget() == this) { dc.updateImeInputAndControlTarget(getImeInputTarget()); mDisplayContent.setImeInputTarget(null); } @@ -1749,6 +1748,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mSession.mPid; } + @Override + public int getUid() { + return mSession.mUid; + } + Task getTask() { return mActivityRecord != null ? mActivityRecord.getTask() : null; } @@ -2348,7 +2352,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override public void onConfigurationChanged(Configuration newParentConfig) { - if (getDisplayContent().getImeTarget(IME_TARGET_INPUT) != this && !isImeLayeringTarget()) { + if (getDisplayContent().getImeInputTarget() != this && !isImeLayeringTarget()) { super.onConfigurationChanged(newParentConfig); return; } @@ -2424,7 +2428,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP dc.setImeLayeringTarget(null); dc.computeImeTarget(true /* updateImeTarget */); } - if (dc.getImeTarget(IME_TARGET_INPUT) == this) { + if (dc.getImeInputTarget() == this) { dc.updateImeInputAndControlTarget(null); } @@ -5596,7 +5600,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * @return {@link InsetsControlTarget} of host that controls the IME. * When window is doesn't have a parent, it is returned as-is. */ - InsetsControlTarget getImeControlTarget() { + @Override + public InsetsControlTarget getImeControlTarget() { return getDisplayContent().getImeHostOrFallback(this); } @@ -5731,8 +5736,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } WindowState getImeInputTarget() { - final InsetsControlTarget target = mDisplayContent.getImeTarget(IME_TARGET_INPUT); - return target != null ? target.getWindow() : null; + final InputTarget target = mDisplayContent.getImeInputTarget(); + return target != null ? target.getWindowState() : null; } void forceReportingResized() { @@ -6117,4 +6122,37 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; mGivenTouchableRegion.setEmpty(); } + + @Override + public boolean shouldControlIme() { + return !inMultiWindowMode(); + } + + @Override + public boolean canScreenshotIme() { + return !isSecureLocked(); + } + + @Override + public ActivityRecord getActivityRecord() { + return mActivityRecord; + } + + @Override + public void unfreezeInsetsAfterStartInput() { + if (mActivityRecord != null) { + mActivityRecord.mImeInsetsFrozenUntilStartInput = false; + } + } + + @Override + public boolean isInputMethodClientFocus(int uid, int pid) { + return getDisplayContent().isInputMethodClientFocus(uid, pid); + } + + @Override + public void dumpProto(ProtoOutputStream proto, long fieldId, + @WindowTraceLogLevel int logLevel) { + dumpDebug(proto, fieldId, logLevel); + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index ef61fbfa53ac..1ac0c26164c1 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -214,6 +214,7 @@ import android.app.admin.StartInstallingUpdateCallback; import android.app.admin.SystemUpdateInfo; import android.app.admin.SystemUpdatePolicy; import android.app.admin.UnsafeStateException; +import android.app.admin.WifiSsidPolicy; import android.app.backup.IBackupManager; import android.app.compat.CompatChanges; import android.app.role.RoleManager; @@ -269,6 +270,7 @@ import android.net.Uri; import android.net.VpnManager; import android.net.metrics.IpConnectivityLog; import android.net.wifi.WifiManager; +import android.net.wifi.WifiSsid; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -389,6 +391,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Constructor; +import java.nio.charset.StandardCharsets; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; @@ -18514,9 +18517,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { ); } - private void validateCurrentWifiMeetsAdminRequirements() { + private void notifyMinimumRequiredWifiSecurityLevelChanged(int level) { mInjector.binderWithCleanCallingIdentity( - () -> mInjector.getWifiManager().validateCurrentWifiMeetsAdminRequirements()); + () -> mInjector.getWifiManager() + .notifyMinimumRequiredWifiSecurityLevelChanged(level)); + } + + private void notifyWifiSsidPolicyChanged(int policyType, List<String> ssids) { + List<WifiSsid> wifiSsidList = new ArrayList<>(); + for (String ssid : ssids) { + wifiSsidList.add( + WifiSsid.fromBytes(ssid.getBytes(StandardCharsets.UTF_8))); + } + WifiSsidPolicy policy = new WifiSsidPolicy(policyType, new ArraySet<>(wifiSsidList)); + mInjector.binderWithCleanCallingIdentity( + () -> mInjector.getWifiManager().notifyWifiSsidPolicyChanged(policy)); } @Override @@ -18536,7 +18551,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { valueChanged = true; } } - if (valueChanged) validateCurrentWifiMeetsAdminRequirements(); + if (valueChanged) notifyMinimumRequiredWifiSecurityLevelChanged(level); } @Override @@ -18568,7 +18583,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } if (changed) saveSettingsLocked(caller.getUserId()); } - if (changed) validateCurrentWifiMeetsAdminRequirements(); + if (changed && !ssids.isEmpty()) { + notifyWifiSsidPolicyChanged(WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids); + } } @Override @@ -18607,7 +18624,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } if (changed) saveSettingsLocked(caller.getUserId()); } - if (changed) validateCurrentWifiMeetsAdminRequirements(); + if (changed) { + notifyWifiSsidPolicyChanged(WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, ssids); + } } @Override diff --git a/services/proguard.flags b/services/proguard.flags index 0e081f182d0d..425da6c11177 100644 --- a/services/proguard.flags +++ b/services/proguard.flags @@ -40,9 +40,15 @@ # Global entities normally kept through explicit Manifest entries # TODO(b/210510433): Revisit and consider generating from frameworks/base/core/res/AndroidManifest.xml, # by including that manifest with the library rule that triggers optimization. --keep,allowoptimization,allowaccessmodification class * extends android.app.backup.BackupAgent --keep,allowoptimization,allowaccessmodification class * extends android.content.BroadcastReceiver --keep,allowoptimization,allowaccessmodification class * extends android.content.ContentProvider +-keep,allowoptimization,allowaccessmodification class com.android.server.** extends android.app.Activity +-keep,allowoptimization,allowaccessmodification class com.android.server.** extends android.app.Service +-keep,allowoptimization,allowaccessmodification class com.android.server.** extends android.app.backup.BackupAgent +-keep,allowoptimization,allowaccessmodification class com.android.server.** extends android.content.BroadcastReceiver +-keep,allowoptimization,allowaccessmodification class com.android.server.** extends android.content.ContentProvider +-keep,allowoptimization,allowaccessmodification class com.android.server.** extends android.preference.Preference +-keep,allowoptimization,allowaccessmodification class com.android.server.** extends android.view.View { + public <init>(...); +} # Various classes subclassed in or referenced via JNI in ethernet-service -keep public class android.net.** { *; } @@ -67,6 +73,7 @@ -keep,allowoptimization,allowaccessmodification class com.android.server.location.gnss.GnssConfiguration$HalInterfaceVersion { *; } -keep,allowoptimization,allowaccessmodification class com.android.server.location.gnss.GnssPowerStats { *; } -keep,allowoptimization,allowaccessmodification class com.android.server.location.gnss.hal.GnssNative { *; } +-keep,allowoptimization,allowaccessmodification class com.android.server.pm.PackageManagerShellCommandDataLoader { *; } -keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorManagerInternal$ProximityActiveListener { *; } -keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorService { *; } -keep,allowoptimization,allowaccessmodification class com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareImpl$AudioSessionProvider$AudioSession { *; } diff --git a/services/tests/inprocesstests/AndroidTest.xml b/services/tests/inprocesstests/AndroidTest.xml index b541512fdc9e..f5fea1bed445 100644 --- a/services/tests/inprocesstests/AndroidTest.xml +++ b/services/tests/inprocesstests/AndroidTest.xml @@ -18,6 +18,8 @@ <option name="test-suite-tag" value="apct" /> <option name="test-suite-tag" value="apct-instrumentation" /> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true"/> <option name="test-file-name" value="FrameworksInProcessTests.apk"/> diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java index a0ac50634a7b..9a4f8e261124 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java @@ -16,11 +16,6 @@ package com.android.server.job.controllers; -import static android.app.job.JobInfo.PRIORITY_DEFAULT; -import static android.app.job.JobInfo.PRIORITY_HIGH; -import static android.app.job.JobInfo.PRIORITY_LOW; -import static android.app.job.JobInfo.PRIORITY_MIN; - import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -275,14 +270,14 @@ public class QuotaControllerTest { } private void setCharging() { - when(mJobSchedulerService.isBatteryCharging()).thenReturn(true); + doReturn(true).when(mJobSchedulerService).isBatteryCharging(); synchronized (mQuotaController.mLock) { mQuotaController.onBatteryStateChangedLocked(); } } private void setDischarging() { - when(mJobSchedulerService.isBatteryCharging()).thenReturn(false); + doReturn(false).when(mJobSchedulerService).isBatteryCharging(); synchronized (mQuotaController.mLock) { mQuotaController.onBatteryStateChangedLocked(); } @@ -415,14 +410,6 @@ public class QuotaControllerTest { } } - private void setDeviceConfigFloat(String key, float val) { - mDeviceConfigPropertiesBuilder.setFloat(key, val); - synchronized (mQuotaController.mLock) { - mQuotaController.prepareForUpdatedConstantsLocked(); - mQcConstants.processConstantLocked(mDeviceConfigPropertiesBuilder.build(), key); - } - } - private void waitForNonDelayedMessagesProcessed() { mQuotaController.getHandler().runWithScissors(() -> {}, 15_000); } @@ -861,7 +848,7 @@ public class QuotaControllerTest { SOURCE_USER_ID, SOURCE_PACKAGE, inputStats); assertEquals(expectedStats, inputStats); assertTrue(mQuotaController.isWithinQuotaLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX)); } assertTrue("Job not ready: " + jobStatus, jobStatus.isReady()); } @@ -885,7 +872,7 @@ public class QuotaControllerTest { assertEquals(expectedStats, inputStats); assertFalse( mQuotaController.isWithinQuotaLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX)); } // Quota should be exceeded due to activity in active timer. @@ -910,7 +897,7 @@ public class QuotaControllerTest { assertEquals(expectedStats, inputStats); assertFalse( mQuotaController.isWithinQuotaLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX)); assertFalse("Job unexpectedly ready: " + jobStatus, jobStatus.isReady()); } } @@ -1508,7 +1495,7 @@ public class QuotaControllerTest { SOURCE_USER_ID, SOURCE_PACKAGE)); assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 30 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE)); } } @@ -1541,7 +1528,7 @@ public class QuotaControllerTest { SOURCE_USER_ID, SOURCE_PACKAGE)); assertEquals(MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE)); } setStandbyBucket(FREQUENT_INDEX); @@ -1551,7 +1538,7 @@ public class QuotaControllerTest { SOURCE_USER_ID, SOURCE_PACKAGE)); assertEquals(MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE)); } setStandbyBucket(WORKING_INDEX); @@ -1561,7 +1548,7 @@ public class QuotaControllerTest { SOURCE_USER_ID, SOURCE_PACKAGE)); assertEquals(7 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE)); } // ACTIVE window = allowed time, so jobs can essentially run non-stop until they reach the @@ -1573,7 +1560,7 @@ public class QuotaControllerTest { SOURCE_USER_ID, SOURCE_PACKAGE)); assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 9 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE)); } } @@ -1597,7 +1584,7 @@ public class QuotaControllerTest { // Max time will phase out, so should use bucket limit. assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE)); } mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear(); @@ -1613,7 +1600,7 @@ public class QuotaControllerTest { SOURCE_USER_ID, SOURCE_PACKAGE)); assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE)); } mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear(); @@ -1630,7 +1617,7 @@ public class QuotaControllerTest { SOURCE_USER_ID, SOURCE_PACKAGE)); assertEquals(3 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE)); } } @@ -1663,7 +1650,7 @@ public class QuotaControllerTest { // window time. assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE)); } mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear(); @@ -1690,107 +1677,7 @@ public class QuotaControllerTest { // Max time only has one minute phase out. Bucket time has 2 minute phase out. assertEquals(9 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); - } - } - - /** - * Test getTimeUntilQuotaConsumedLocked when the determination is based on the job's priority. - */ - @Test - public void testGetTimeUntilQuotaConsumedLocked_Priority() { - final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); - // Close to RARE boundary. - mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, - createTimingSession(now - (24 * HOUR_IN_MILLIS - 30 * SECOND_IN_MILLIS), - 150 * SECOND_IN_MILLIS, 5), false); - // Far away from FREQUENT boundary. - mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, - createTimingSession(now - (7 * HOUR_IN_MILLIS), 2 * MINUTE_IN_MILLIS, 5), false); - // Overlap WORKING_SET boundary. - mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, - createTimingSession(now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), - 2 * MINUTE_IN_MILLIS, 5), false); - // Close to ACTIVE boundary. - mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, - createTimingSession(now - (9 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false); - - setStandbyBucket(RARE_INDEX); - synchronized (mQuotaController.mLock) { - assertEquals(30 * SECOND_IN_MILLIS, - mQuotaController.getRemainingExecutionTimeLocked( - SOURCE_USER_ID, SOURCE_PACKAGE)); - assertEquals(3 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_HIGH)); - assertEquals(3 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); - assertEquals(0, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_LOW)); - assertEquals(0, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_MIN)); - } - - setStandbyBucket(FREQUENT_INDEX); - synchronized (mQuotaController.mLock) { - assertEquals(3 * MINUTE_IN_MILLIS, - mQuotaController.getRemainingExecutionTimeLocked( - SOURCE_USER_ID, SOURCE_PACKAGE)); - assertEquals(3 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_HIGH)); - assertEquals(3 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); - assertEquals(30 * SECOND_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_LOW)); - assertEquals(0, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_MIN)); - } - - setStandbyBucket(WORKING_INDEX); - synchronized (mQuotaController.mLock) { - assertEquals(6 * MINUTE_IN_MILLIS, - mQuotaController.getRemainingExecutionTimeLocked( SOURCE_USER_ID, SOURCE_PACKAGE)); - assertEquals(7 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_HIGH)); - assertEquals(7 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); - assertEquals(4 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_LOW)); - assertEquals(2 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_MIN)); - } - - // ACTIVE window = allowed time, so jobs can essentially run non-stop until they reach the - // max execution time. - setStandbyBucket(ACTIVE_INDEX); - synchronized (mQuotaController.mLock) { - assertEquals(7 * MINUTE_IN_MILLIS, - mQuotaController.getRemainingExecutionTimeLocked( - SOURCE_USER_ID, SOURCE_PACKAGE)); - assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 7 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_HIGH)); - assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 7 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); - assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 7 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_LOW)); - assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 7 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_MIN)); } } @@ -1820,7 +1707,7 @@ public class QuotaControllerTest { SOURCE_USER_ID, SOURCE_PACKAGE)); assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 10 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE)); } } @@ -1842,7 +1729,7 @@ public class QuotaControllerTest { SOURCE_USER_ID, SOURCE_PACKAGE)); assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE)); } mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, @@ -1854,7 +1741,7 @@ public class QuotaControllerTest { SOURCE_USER_ID, SOURCE_PACKAGE)); assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE)); } mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, @@ -1867,7 +1754,7 @@ public class QuotaControllerTest { SOURCE_USER_ID, SOURCE_PACKAGE)); assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE)); } mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, @@ -1882,15 +1769,15 @@ public class QuotaControllerTest { SOURCE_USER_ID, SOURCE_PACKAGE)); assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 30 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, PRIORITY_DEFAULT)); + SOURCE_USER_ID, SOURCE_PACKAGE)); } } @Test public void testIsWithinQuotaLocked_NeverApp() { synchronized (mQuotaController.mLock) { - assertFalse(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test.never", NEVER_INDEX, PRIORITY_DEFAULT)); + assertFalse( + mQuotaController.isWithinQuotaLocked(0, "com.android.test.never", NEVER_INDEX)); } } @@ -1898,8 +1785,7 @@ public class QuotaControllerTest { public void testIsWithinQuotaLocked_Charging() { setCharging(); synchronized (mQuotaController.mLock) { - assertTrue(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", RARE_INDEX, PRIORITY_DEFAULT)); + assertTrue(mQuotaController.isWithinQuotaLocked(0, "com.android.test", RARE_INDEX)); } } @@ -1913,8 +1799,7 @@ public class QuotaControllerTest { createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false); synchronized (mQuotaController.mLock) { mQuotaController.incrementJobCountLocked(0, "com.android.test", 5); - assertTrue(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", WORKING_INDEX, PRIORITY_DEFAULT)); + assertTrue(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX)); } } @@ -1931,7 +1816,7 @@ public class QuotaControllerTest { synchronized (mQuotaController.mLock) { mQuotaController.incrementJobCountLocked(0, "com.android.test.spam", jobCount); assertFalse(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test.spam", WORKING_INDEX, PRIORITY_DEFAULT)); + 0, "com.android.test.spam", WORKING_INDEX)); } mQuotaController.saveTimingSession(0, "com.android.test.frequent", @@ -1941,7 +1826,7 @@ public class QuotaControllerTest { createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 500), false); synchronized (mQuotaController.mLock) { assertFalse(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test.frequent", FREQUENT_INDEX, PRIORITY_DEFAULT)); + 0, "com.android.test.frequent", FREQUENT_INDEX)); } } @@ -1957,8 +1842,7 @@ public class QuotaControllerTest { createTimingSession(now - (5 * MINUTE_IN_MILLIS), 4 * MINUTE_IN_MILLIS, 5), false); synchronized (mQuotaController.mLock) { mQuotaController.incrementJobCountLocked(0, "com.android.test", 5); - assertFalse(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", WORKING_INDEX, PRIORITY_DEFAULT)); + assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX)); } } @@ -1974,8 +1858,7 @@ public class QuotaControllerTest { false); synchronized (mQuotaController.mLock) { mQuotaController.incrementJobCountLocked(0, "com.android.test", jobCount); - assertFalse(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", WORKING_INDEX, PRIORITY_DEFAULT)); + assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX)); } } @@ -2128,66 +2011,22 @@ public class QuotaControllerTest { assertEquals("Rare has incorrect quota status with " + (i + 1) + " sessions", i < 2, - mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", RARE_INDEX, PRIORITY_DEFAULT)); + mQuotaController.isWithinQuotaLocked(0, "com.android.test", RARE_INDEX)); assertEquals("Frequent has incorrect quota status with " + (i + 1) + " sessions", i < 3, mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", FREQUENT_INDEX, PRIORITY_DEFAULT)); + 0, "com.android.test", FREQUENT_INDEX)); assertEquals("Working has incorrect quota status with " + (i + 1) + " sessions", i < 4, - mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", WORKING_INDEX, PRIORITY_DEFAULT)); + mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX)); assertEquals("Active has incorrect quota status with " + (i + 1) + " sessions", i < 5, - mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", ACTIVE_INDEX, PRIORITY_DEFAULT)); + mQuotaController.isWithinQuotaLocked(0, "com.android.test", ACTIVE_INDEX)); } } } @Test - public void testIsWithinQuotaLocked_Priority() { - setDischarging(); - final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQuotaController.saveTimingSession(0, "com.android.test", - createTimingSession(now - (7 * HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false); - mQuotaController.saveTimingSession(0, "com.android.test", - createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false); - mQuotaController.saveTimingSession(0, "com.android.test", - createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false); - synchronized (mQuotaController.mLock) { - mQuotaController.incrementJobCountLocked(0, "com.android.test", 5); - assertTrue(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", FREQUENT_INDEX, PRIORITY_HIGH)); - assertTrue(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", FREQUENT_INDEX, PRIORITY_DEFAULT)); - assertFalse(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", FREQUENT_INDEX, PRIORITY_LOW)); - assertFalse(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", FREQUENT_INDEX, PRIORITY_MIN)); - - assertTrue(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", WORKING_INDEX, PRIORITY_HIGH)); - assertTrue(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", WORKING_INDEX, PRIORITY_DEFAULT)); - assertTrue(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", WORKING_INDEX, PRIORITY_LOW)); - assertFalse(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", WORKING_INDEX, PRIORITY_MIN)); - - assertTrue(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", ACTIVE_INDEX, PRIORITY_HIGH)); - assertTrue(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", ACTIVE_INDEX, PRIORITY_DEFAULT)); - assertTrue(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", ACTIVE_INDEX, PRIORITY_LOW)); - assertTrue(mQuotaController.isWithinQuotaLocked( - 0, "com.android.test", ACTIVE_INDEX, PRIORITY_MIN)); - } - } - - @Test public void testIsWithinEJQuotaLocked_NeverApp() { JobStatus js = createExpeditedJobStatus("testIsWithinEJQuotaLocked_NeverApp", 1); setStandbyBucket(NEVER_INDEX, js); @@ -2737,8 +2576,7 @@ public class QuotaControllerTest { mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, createTimingSession(now - 25 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1), false); synchronized (mQuotaController.mLock) { - mQuotaController.maybeScheduleStartAlarmLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); } verify(mAlarmManager, timeout(1000).times(0)).setWindow( anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); @@ -2790,128 +2628,6 @@ public class QuotaControllerTest { anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); } - @Test - public void testMaybeScheduleStartAlarmLocked_Priority() { - // saveTimingSession calls maybeScheduleCleanupAlarmLocked which interferes with these tests - // because it schedules an alarm too. Prevent it from doing so. - spyOn(mQuotaController); - doNothing().when(mQuotaController).maybeScheduleCleanupAlarmLocked(); - - setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_RARE, 5); - - final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, - createTimingSession(now - (24 * HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 1), false); - mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, - createTimingSession(now - (7 * HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 1), false); - mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, - createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 1), false); - mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, - createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 1), false); - - InOrder inOrder = inOrder(mAlarmManager); - - JobStatus jobDef = createJobStatus("testMaybeScheduleStartAlarmLocked_Priority", - SOURCE_PACKAGE, CALLING_UID, - new JobInfo.Builder(1, new ComponentName(mContext, "TestQuotaJobService")) - .setPriority(PRIORITY_DEFAULT) - .build()); - JobStatus jobLow = createJobStatus("testMaybeScheduleStartAlarmLocked_Priority", - SOURCE_PACKAGE, CALLING_UID, - new JobInfo.Builder(2, new ComponentName(mContext, "TestQuotaJobService")) - .setPriority(PRIORITY_LOW) - .build()); - JobStatus jobMin = createJobStatus("testMaybeScheduleStartAlarmLocked_Priority", - SOURCE_PACKAGE, CALLING_UID, - new JobInfo.Builder(3, new ComponentName(mContext, "TestQuotaJobService")) - .setPriority(PRIORITY_MIN) - .build()); - - setStandbyBucket(RARE_INDEX, jobDef, jobLow, jobMin); - synchronized (mQuotaController.mLock) { - mQuotaController.maybeStartTrackingJobLocked(jobMin, null); - mQuotaController.maybeScheduleStartAlarmLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX); - // Min job requires 5 mins of surplus. - long expectedAlarmTime = now + 23 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS; - inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow( - anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); - - mQuotaController.maybeStartTrackingJobLocked(jobLow, null); - mQuotaController.maybeScheduleStartAlarmLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX); - // Low job requires 2.5 mins of surplus. - expectedAlarmTime = now + 17 * HOUR_IN_MILLIS + 90 * SECOND_IN_MILLIS; - inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow( - anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); - - mQuotaController.maybeStartTrackingJobLocked(jobDef, null); - mQuotaController.maybeScheduleStartAlarmLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX); - // Default+ jobs require IN_QUOTA_BUFFER_MS. - expectedAlarmTime = now + mQcConstants.IN_QUOTA_BUFFER_MS; - inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow( - anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); - - mQuotaController.maybeStopTrackingJobLocked(jobMin, null, false); - mQuotaController.maybeStopTrackingJobLocked(jobLow, null, false); - mQuotaController.maybeStopTrackingJobLocked(jobDef, null, false); - - setStandbyBucket(FREQUENT_INDEX, jobDef, jobLow, jobMin); - - mQuotaController.maybeStartTrackingJobLocked(jobMin, null); - mQuotaController.maybeScheduleStartAlarmLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, FREQUENT_INDEX); - // Min job requires 5 mins of surplus. - expectedAlarmTime = now + 7 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS; - inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow( - anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); - - mQuotaController.maybeStartTrackingJobLocked(jobLow, null); - mQuotaController.maybeScheduleStartAlarmLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, FREQUENT_INDEX); - // Low job requires 2.5 mins of surplus. - expectedAlarmTime = now + HOUR_IN_MILLIS + 90 * SECOND_IN_MILLIS; - inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow( - anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); - - mQuotaController.maybeStartTrackingJobLocked(jobDef, null); - mQuotaController.maybeScheduleStartAlarmLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, FREQUENT_INDEX); - // Default+ jobs already have enough quota. - inOrder.verify(mAlarmManager, timeout(1000).times(0)).setWindow( - anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); - - mQuotaController.maybeStopTrackingJobLocked(jobMin, null, false); - mQuotaController.maybeStopTrackingJobLocked(jobLow, null, false); - mQuotaController.maybeStopTrackingJobLocked(jobDef, null, false); - - setStandbyBucket(WORKING_INDEX, jobDef, jobLow, jobMin); - - mQuotaController.maybeStartTrackingJobLocked(jobMin, null); - mQuotaController.maybeScheduleStartAlarmLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX); - // Min job requires 5 mins of surplus. - expectedAlarmTime = now + HOUR_IN_MILLIS + MINUTE_IN_MILLIS; - inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow( - anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); - - mQuotaController.maybeStartTrackingJobLocked(jobLow, null); - mQuotaController.maybeScheduleStartAlarmLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX); - // Low job has enough surplus. - inOrder.verify(mAlarmManager, timeout(1000).times(0)).setWindow( - anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); - - mQuotaController.maybeStartTrackingJobLocked(jobDef, null); - mQuotaController.maybeScheduleStartAlarmLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX); - // Default+ jobs already have enough quota. - inOrder.verify(mAlarmManager, timeout(1000).times(0)).setWindow( - anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); - } - } - /** Tests that the start alarm is properly rescheduled if the app's bucket is changed. */ @Test public void testMaybeScheduleStartAlarmLocked_BucketChange() { @@ -3212,8 +2928,6 @@ public class QuotaControllerTest { setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_RESTRICTED_MS, 11 * MINUTE_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_IN_QUOTA_BUFFER_MS, 2 * MINUTE_IN_MILLIS); - setDeviceConfigFloat(QcConstants.KEY_ALLOWED_TIME_SURPLUS_PRIORITY_LOW, .7f); - setDeviceConfigFloat(QcConstants.KEY_ALLOWED_TIME_SURPLUS_PRIORITY_MIN, .2f); setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_EXEMPTED_MS, 99 * MINUTE_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_ACTIVE_MS, 15 * MINUTE_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_WORKING_MS, 30 * MINUTE_IN_MILLIS); @@ -3269,8 +2983,6 @@ public class QuotaControllerTest { assertEquals(11 * MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs()[RESTRICTED_INDEX]); assertEquals(2 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs()); - assertEquals(.7f, mQuotaController.getAllowedTimeSurplusPriorityLow(), 1e-6); - assertEquals(.2f, mQuotaController.getAllowedTimeSurplusPriorityMin(), 1e-6); assertEquals(99 * MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[EXEMPTED_INDEX]); assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[ACTIVE_INDEX]); @@ -3327,8 +3039,6 @@ public class QuotaControllerTest { setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_RESTRICTED_MS, -MINUTE_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_IN_QUOTA_BUFFER_MS, -MINUTE_IN_MILLIS); - setDeviceConfigFloat(QcConstants.KEY_ALLOWED_TIME_SURPLUS_PRIORITY_LOW, -.1f); - setDeviceConfigFloat(QcConstants.KEY_ALLOWED_TIME_SURPLUS_PRIORITY_MIN, -.01f); setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_EXEMPTED_MS, -MINUTE_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_ACTIVE_MS, -MINUTE_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_WORKING_MS, -MINUTE_IN_MILLIS); @@ -3379,8 +3089,6 @@ public class QuotaControllerTest { assertEquals(MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs()[RESTRICTED_INDEX]); assertEquals(0, mQuotaController.getInQuotaBufferMs()); - assertEquals(0f, mQuotaController.getAllowedTimeSurplusPriorityLow(), 1e-6); - assertEquals(0f, mQuotaController.getAllowedTimeSurplusPriorityMin(), 1e-6); assertEquals(MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[EXEMPTED_INDEX]); assertEquals(MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[ACTIVE_INDEX]); assertEquals(MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[WORKING_INDEX]); @@ -3451,8 +3159,6 @@ public class QuotaControllerTest { setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_RESTRICTED_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_IN_QUOTA_BUFFER_MS, 25 * HOUR_IN_MILLIS); - setDeviceConfigFloat(QcConstants.KEY_ALLOWED_TIME_SURPLUS_PRIORITY_LOW, 1f); - setDeviceConfigFloat(QcConstants.KEY_ALLOWED_TIME_SURPLUS_PRIORITY_MIN, .95f); setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_EXEMPTED_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_ACTIVE_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_WORKING_MS, 25 * HOUR_IN_MILLIS); @@ -3492,8 +3198,6 @@ public class QuotaControllerTest { assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs()[RESTRICTED_INDEX]); assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs()); - assertEquals(.9f, mQuotaController.getAllowedTimeSurplusPriorityLow(), 1e-6); - assertEquals(.9f, mQuotaController.getAllowedTimeSurplusPriorityMin(), 1e-6); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getBucketWindowSizes()[EXEMPTED_INDEX]); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getBucketWindowSizes()[ACTIVE_INDEX]); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getBucketWindowSizes()[WORKING_INDEX]); diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index 53cab9ed80cf..a6194df18217 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -98,6 +98,8 @@ <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK"/> <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/> + <uses-permission android:name="android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY" /> + <uses-permission android:name="android.permission.READ_NEARBY_STREAMING_POLICY" /> <uses-permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT" /> diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java index 64be56906d4b..eab96c09a00a 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java @@ -40,12 +40,14 @@ import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; @Presubmit @RunWith(AndroidTestingRunner.class) @@ -62,6 +64,9 @@ public class BiometricSchedulerOperationTest { } } + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + @Mock private InterruptableMonitor<FakeHal> mClientMonitor; @Mock @@ -76,7 +81,6 @@ public class BiometricSchedulerOperationTest { @Before public void setUp() { - MockitoAnnotations.initMocks(this); mHandler = new Handler(TestableLooper.get(this).getLooper()); mOperation = new BiometricSchedulerOperation(mClientMonitor, mClientCallback); } @@ -311,10 +315,12 @@ public class BiometricSchedulerOperationTest { private void cancelWatchdog(boolean start) { when(mClientMonitor.getFreshDaemon()).thenReturn(mHal); - mOperation.start(mock(ClientMonitorCallback.class)); + final ClientMonitorCallback opStartCallback = mock(ClientMonitorCallback.class); + mOperation.start(opStartCallback); if (start) { verify(mClientMonitor).start(mStartCallback.capture()); mStartCallback.getValue().onClientStarted(mClientMonitor); + verify(opStartCallback).onClientStarted(eq(mClientMonitor)); } mOperation.cancel(mHandler, mock(ClientMonitorCallback.class)); @@ -325,6 +331,7 @@ public class BiometricSchedulerOperationTest { assertThat(mOperation.isFinished()).isTrue(); assertThat(mOperation.isCanceling()).isFalse(); + verify(opStartCallback).onClientFinished(eq(mClientMonitor), eq(false)); verify(mClientMonitor).destroy(); } } 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 9aac81c34edb..7b921ababf36 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 @@ -58,6 +58,7 @@ import android.os.IBinder; import android.os.IPowerManager; import android.os.IThermalService; import android.os.PowerManager; +import android.os.Process; import android.os.RemoteException; import android.os.WorkSource; import android.platform.test.annotations.Presubmit; @@ -136,6 +137,7 @@ public class VirtualDeviceManagerServiceTest { LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock); mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); + doReturn(mContext).when(mContext).createContextAsUser(eq(Process.myUserHandle()), anyInt()); doNothing().when(mContext).enforceCallingOrSelfPermission( eq(Manifest.permission.CREATE_VIRTUAL_DEVICE), anyString()); when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn( 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 3160272ef9b1..f0c907d49a46 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 @@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat; 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.content.Context; import android.content.ContextWrapper; @@ -72,7 +73,8 @@ public class VirtualAudioControllerTest { /* allowedUsers= */ new ArraySet<>(), /* allowedActivities= */ new ArraySet<>(), /* blockedActivities= */ new ArraySet<>(), - /* activityListener= */null, + VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED, + /* activityListener= */ null, /* activityBlockedCallback= */ null); } diff --git a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java index 0287510041be..bd35be4d0f3e 100644 --- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java +++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java @@ -107,6 +107,7 @@ public class LocaleManagerBackupRestoreTest { private PackageManager mMockPackageManager; @Mock private LocaleManagerService mMockLocaleManagerService; + BroadcastReceiver mUserMonitor; PackageMonitor mPackageMonitor; @@ -131,6 +132,7 @@ public class LocaleManagerBackupRestoreTest { mMockPackageManagerInternal = mock(PackageManagerInternal.class); mMockPackageManager = mock(PackageManager.class); mMockLocaleManagerService = mock(LocaleManagerService.class); + SystemAppUpdateTracker systemAppUpdateTracker = mock(SystemAppUpdateTracker.class); doReturn(mMockPackageManager).when(mMockContext).getPackageManager(); @@ -144,7 +146,8 @@ public class LocaleManagerBackupRestoreTest { doNothing().when(mBackupHelper).notifyBackupManager(); mUserMonitor = mBackupHelper.getUserMonitor(); - mPackageMonitor = new LocaleManagerServicePackageMonitor(mBackupHelper); + mPackageMonitor = new LocaleManagerServicePackageMonitor(mBackupHelper, + systemAppUpdateTracker); setCurrentTimeMillis(DEFAULT_CREATION_TIME_MILLIS); } diff --git a/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java b/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java new file mode 100644 index 000000000000..5185e15a8557 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java @@ -0,0 +1,297 @@ +/* + * 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.locales; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import android.app.ActivityManagerInternal; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.InstallSourceInfo; +import android.content.pm.PackageInstaller; +import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; +import android.os.Binder; +import android.os.Environment; +import android.os.LocaleList; +import android.os.UserHandle; +import android.text.TextUtils; +import android.util.AtomicFile; +import android.util.TypedXmlPullParser; +import android.util.Xml; + +import com.android.internal.content.PackageMonitor; +import com.android.internal.util.XmlUtils; +import com.android.server.wm.ActivityTaskManagerInternal; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Set; + +/** + * Unit tests for {@link SystemAppUpdateTracker}. + */ +public class SystemAppUpdateTrackerTest { + private static final String DEFAULT_PACKAGE_NAME_1 = "com.android.myapp1"; + private static final String DEFAULT_PACKAGE_NAME_2 = "com.android.myapp2"; + private static final String DEFAULT_LOCALE_TAGS = "en-XC,ar-XB"; + private static final LocaleList DEFAULT_LOCALES = + LocaleList.forLanguageTags(DEFAULT_LOCALE_TAGS); + private static final String PACKAGE_XML_TAG = "package"; + private static final String ATTR_NAME = "name"; + private static final String SYSTEM_APPS_XML_TAG = "system_apps"; + private static final int DEFAULT_USER_ID = 0; + + private AtomicFile mStoragefile; + private static final String DEFAULT_INSTALLER_PACKAGE_NAME = "com.android.myapp.installer"; + private static final InstallSourceInfo DEFAULT_INSTALL_SOURCE_INFO = new InstallSourceInfo( + /* initiatingPackageName = */ null, /* initiatingPackageSigningInfo = */ null, + /* originatingPackageName = */ null, + /* installingPackageName = */ DEFAULT_INSTALLER_PACKAGE_NAME, + /* packageSource = */ PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED); + + @Mock + private Context mMockContext; + @Mock + PackageManager mMockPackageManager; + @Mock + private PackageManagerInternal mMockPackageManagerInternal; + @Mock + private ActivityTaskManagerInternal mMockActivityTaskManager; + @Mock + private ActivityManagerInternal mMockActivityManager; + @Mock + private LocaleManagerBackupHelper mMockLocaleManagerBackupHelper; + @Mock + PackageMonitor mMockPackageMonitor; + + private LocaleManagerService mLocaleManagerService; + + // Object under test. + private SystemAppUpdateTracker mSystemAppUpdateTracker; + + @Before + public void setUp() throws Exception { + mMockContext = mock(Context.class); + mMockActivityTaskManager = mock(ActivityTaskManagerInternal.class); + mMockActivityManager = mock(ActivityManagerInternal.class); + mMockPackageManagerInternal = mock(PackageManagerInternal.class); + mMockPackageMonitor = mock(PackageMonitor.class); + mMockLocaleManagerBackupHelper = mock(ShadowLocaleManagerBackupHelper.class); + mLocaleManagerService = new LocaleManagerService(mMockContext, + mMockActivityTaskManager, mMockActivityManager, + mMockPackageManagerInternal, mMockLocaleManagerBackupHelper, mMockPackageMonitor); + + doReturn(DEFAULT_USER_ID).when(mMockActivityManager) + .handleIncomingUser(anyInt(), anyInt(), eq(DEFAULT_USER_ID), anyBoolean(), anyInt(), + anyString(), anyString()); + + mMockPackageManager = mock(PackageManager.class); + doReturn(DEFAULT_INSTALL_SOURCE_INFO).when(mMockPackageManager) + .getInstallSourceInfo(anyString()); + doReturn(mMockPackageManager).when(mMockContext).getPackageManager(); + + mStoragefile = new AtomicFile(new File( + Environment.getExternalStorageDirectory(), "systemUpdateUnitTests.xml")); + + mSystemAppUpdateTracker = new SystemAppUpdateTracker(mMockContext, + mLocaleManagerService, mStoragefile); + } + + @After + public void tearDown() { + mStoragefile.delete(); + } + + @Test + public void testInit_loadsCorrectly() throws Exception { + doReturn(createApplicationInfoForApp(DEFAULT_PACKAGE_NAME_1, + /* isUpdatedSystemApp = */ true)) + .when(mMockPackageManager).getApplicationInfo(eq(DEFAULT_PACKAGE_NAME_1), any()); + + // Updates the app once so that it writes to the file. + mSystemAppUpdateTracker.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1, + Binder.getCallingUid()); + // Clear the in-memory data of updated apps + mSystemAppUpdateTracker.getUpdatedApps().clear(); + // Invoke init to verify if it correctly populates in-memory set. + mSystemAppUpdateTracker.init(); + + assertEquals(Set.of(DEFAULT_PACKAGE_NAME_1), mSystemAppUpdateTracker.getUpdatedApps()); + } + + @Test + public void testOnPackageUpdatedFinished_systemAppFirstUpdate_writesToFile() throws Exception { + doReturn(createApplicationInfoForApp(DEFAULT_PACKAGE_NAME_1, + /* isUpdatedSystemApp = */ true)) + .when(mMockPackageManager).getApplicationInfo(eq(DEFAULT_PACKAGE_NAME_1), any()); + doReturn(new ActivityTaskManagerInternal.PackageConfig(/* nightMode = */ 0, + DEFAULT_LOCALES)).when(mMockActivityTaskManager) + .getApplicationConfig(anyString(), anyInt()); + + mSystemAppUpdateTracker.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1, + Binder.getCallingUid()); + + assertBroadcastSentToInstaller(DEFAULT_PACKAGE_NAME_1, DEFAULT_LOCALES); + Set<String> expectedAppList = Set.of(DEFAULT_PACKAGE_NAME_1); + assertEquals(expectedAppList, mSystemAppUpdateTracker.getUpdatedApps()); + verifyStorageFileContents(expectedAppList); + } + + @Test + public void testOnPackageUpdatedFinished_systemAppSecondUpdate_doesNothing() throws Exception { + doReturn(createApplicationInfoForApp(DEFAULT_PACKAGE_NAME_1, + /* isUpdatedSystemApp = */ true)) + .when(mMockPackageManager).getApplicationInfo(eq(DEFAULT_PACKAGE_NAME_1), any()); + doReturn(new ActivityTaskManagerInternal.PackageConfig(/* nightMode = */ 0, + DEFAULT_LOCALES)).when(mMockActivityTaskManager) + .getApplicationConfig(anyString(), anyInt()); + + // first update + mSystemAppUpdateTracker.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1, + Binder.getCallingUid()); + + assertBroadcastSentToInstaller(DEFAULT_PACKAGE_NAME_1, DEFAULT_LOCALES); + Set<String> expectedAppList = Set.of(DEFAULT_PACKAGE_NAME_1); + assertEquals(expectedAppList, mSystemAppUpdateTracker.getUpdatedApps()); + verifyStorageFileContents(expectedAppList); + + // second update + mSystemAppUpdateTracker.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1, + Binder.getCallingUid()); + // getApplicationLocales should be invoked only once on the first update. + verify(mMockActivityTaskManager, times(1)) + .getApplicationConfig(anyString(), anyInt()); + // Broadcast should be sent only once on first update. + verify(mMockContext, times(1)).sendBroadcastAsUser(any(), any()); + // Verify that the content remains the same. + verifyStorageFileContents(expectedAppList); + } + + @Test + public void testOnPackageUpdatedFinished_notSystemApp_doesNothing() throws Exception { + doReturn(createApplicationInfoForApp(DEFAULT_PACKAGE_NAME_2, + /* isUpdatedSystemApp = */false)) + .when(mMockPackageManager).getApplicationInfo(eq(DEFAULT_PACKAGE_NAME_2), any()); + + mSystemAppUpdateTracker.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_2, + Binder.getCallingUid()); + + assertTrue(!mSystemAppUpdateTracker.getUpdatedApps().contains(DEFAULT_PACKAGE_NAME_2)); + // getApplicationLocales should be never be invoked if not a system app. + verifyZeroInteractions(mMockActivityTaskManager); + // Broadcast should be never sent if not a system app. + verify(mMockContext, never()).sendBroadcastAsUser(any(), any()); + // It shouldn't write to the file if not a system app. + assertTrue(!mStoragefile.getBaseFile().isFile()); + } + + @Test + public void testOnPackageUpdatedFinished_noInstaller_doesNothing() throws Exception { + doReturn(createApplicationInfoForApp(DEFAULT_PACKAGE_NAME_1, + /* isUpdatedSystemApp = */ true)) + .when(mMockPackageManager).getApplicationInfo(eq(DEFAULT_PACKAGE_NAME_1), any()); + doReturn(null).when(mMockPackageManager).getInstallSourceInfo(anyString()); + + mSystemAppUpdateTracker.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1, + Binder.getCallingUid()); + + // getApplicationLocales should be never be invoked if not installer is not present. + verifyZeroInteractions(mMockActivityTaskManager); + // Broadcast should be never sent if installer is not present. + verify(mMockContext, never()).sendBroadcastAsUser(any(), any()); + // It shouldn't write to file if no installer present. + assertTrue(!mStoragefile.getBaseFile().isFile()); + } + + private void verifyStorageFileContents(Set<String> expectedAppList) + throws IOException, XmlPullParserException { + assertTrue(mStoragefile.getBaseFile().isFile()); + try (InputStream storageInputStream = mStoragefile.openRead()) { + assertEquals(expectedAppList, readFromXml(storageInputStream)); + } catch (IOException | XmlPullParserException e) { + throw e; + } + } + + private Set<String> readFromXml(InputStream storageInputStream) + throws XmlPullParserException, IOException { + Set<String> outputList = new HashSet<>(); + final TypedXmlPullParser parser = Xml.newFastPullParser(); + parser.setInput(storageInputStream, StandardCharsets.UTF_8.name()); + XmlUtils.beginDocument(parser, SYSTEM_APPS_XML_TAG); + int depth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, depth)) { + if (parser.getName().equals(PACKAGE_XML_TAG)) { + String packageName = parser.getAttributeValue(/* namespace= */ null, + ATTR_NAME); + if (!TextUtils.isEmpty(packageName)) { + outputList.add(packageName); + } + } + } + return outputList; + } + + /** + * Verifies the broadcast sent to the installer of the updated app. + */ + private void assertBroadcastSentToInstaller(String packageName, LocaleList locales) { + ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); + verify(mMockContext).sendBroadcastAsUser(captor.capture(), any(UserHandle.class)); + for (Intent intent : captor.getAllValues()) { + assertTrue(Intent.ACTION_APPLICATION_LOCALE_CHANGED.equals(intent.getAction())); + assertTrue(DEFAULT_INSTALLER_PACKAGE_NAME.equals(intent.getPackage())); + assertTrue(packageName.equals(intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME))); + assertTrue(locales.equals(intent.getParcelableExtra(Intent.EXTRA_LOCALE_LIST))); + } + } + + private ApplicationInfo createApplicationInfoForApp(String packageName, + boolean isUpdatedSystemApp) { + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.packageName = packageName; + if (isUpdatedSystemApp) { + applicationInfo.flags = ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + } + return applicationInfo; + } +} diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java index 5d4ffbb6aca2..b7cfbaf4887f 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java @@ -285,7 +285,7 @@ public class VibrationSettingsTest { } @Test - public void shouldIgnoreVibration_withRingerModeSilent_ignoresRingtoneAndTouch() { + public void shouldIgnoreVibration_withRingerModeSilent_ignoresRingtoneOnly() { // Vibrating settings on are overruled by ringer mode. setUserSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, 1); setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1); @@ -293,7 +293,7 @@ public class VibrationSettingsTest { setRingerMode(AudioManager.RINGER_MODE_SILENT); for (int usage : ALL_USAGES) { - if (usage == USAGE_RINGTONE || usage == USAGE_TOUCH) { + if (usage == USAGE_RINGTONE) { assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_RINGER_MODE); } else { assertVibrationNotIgnoredForUsage(usage); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java index 721641a7a8c8..5458a5b84eea 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java @@ -174,7 +174,7 @@ public class GroupHelperTest extends UiServiceTestCase { } verify(mCallback, times(AUTOGROUP_AT_COUNT + 1)) - .updateAutogroupSummary(anyString(), eq(true)); + .updateAutogroupSummary(anyInt(), anyString(), eq(true)); int userId = UserHandle.SYSTEM.getIdentifier(); assertEquals(mGroupHelper.getOngoingGroupCount( @@ -203,7 +203,7 @@ public class GroupHelperTest extends UiServiceTestCase { mGroupHelper.onNotificationUpdated(notifications.get(0), true); verify(mCallback, times(AUTOGROUP_AT_COUNT + 2)) - .updateAutogroupSummary(anyString(), eq(true)); + .updateAutogroupSummary(anyInt(), anyString(), eq(true)); int userId = UserHandle.SYSTEM.getIdentifier(); assertEquals(mGroupHelper.getOngoingGroupCount( @@ -236,7 +236,7 @@ public class GroupHelperTest extends UiServiceTestCase { mGroupHelper.onNotificationUpdated(notifications.get(0), true); verify(mCallback, times(AUTOGROUP_AT_COUNT + 3)) - .updateAutogroupSummary(anyString(), eq(true)); + .updateAutogroupSummary(anyInt(), anyString(), eq(true)); int userId = UserHandle.SYSTEM.getIdentifier(); assertEquals(mGroupHelper.getOngoingGroupCount( @@ -263,7 +263,7 @@ public class GroupHelperTest extends UiServiceTestCase { mGroupHelper.onNotificationRemoved(notifications.get(0)); verify(mCallback, times(AUTOGROUP_AT_COUNT + 2)) - .updateAutogroupSummary(anyString(), eq(true)); + .updateAutogroupSummary(anyInt(), anyString(), eq(true)); int userId = UserHandle.SYSTEM.getIdentifier(); assertEquals(mGroupHelper.getOngoingGroupCount( @@ -291,7 +291,7 @@ public class GroupHelperTest extends UiServiceTestCase { mGroupHelper.onNotificationUpdated(notifications.get(0), true); verify(mCallback, times(1)) - .updateAutogroupSummary(anyString(), eq(true)); + .updateAutogroupSummary(anyInt(), anyString(), eq(true)); int userId = UserHandle.SYSTEM.getIdentifier(); assertEquals(mGroupHelper.getOngoingGroupCount( @@ -315,7 +315,7 @@ public class GroupHelperTest extends UiServiceTestCase { } verify(mCallback, times(1)) - .updateAutogroupSummary(anyString(), eq(true)); + .updateAutogroupSummary(anyInt(), anyString(), eq(true)); int userId = UserHandle.SYSTEM.getIdentifier(); assertEquals(mGroupHelper.getOngoingGroupCount( @@ -339,7 +339,7 @@ public class GroupHelperTest extends UiServiceTestCase { } verify(mCallback, times(0)) - .updateAutogroupSummary(anyString(), eq(true)); + .updateAutogroupSummary(anyInt(), anyString(), eq(true)); int userId = UserHandle.SYSTEM.getIdentifier(); assertEquals(mGroupHelper.getOngoingGroupCount(userId, pkg, AUTOGROUP_KEY), 0); diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp index 90dac47e353c..57bbe40c5b06 100644 --- a/services/tests/wmtests/Android.bp +++ b/services/tests/wmtests/Android.bp @@ -57,6 +57,7 @@ android_test { "ub-uiautomator", "hamcrest-library", "platform-compat-test-rules", + "CtsSurfaceValidatorLib", ], libs: [ diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml index c2298d0f3d20..2918365b94c8 100644 --- a/services/tests/wmtests/AndroidManifest.xml +++ b/services/tests/wmtests/AndroidManifest.xml @@ -43,6 +43,8 @@ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" /> <uses-permission android:name="android.permission.CAPTURE_BLACKOUT_CONTENT"/> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) --> <application android:debuggable="true" @@ -78,6 +80,12 @@ android:turnScreenOn="true" android:showWhenLocked="true" /> <activity android:name="com.android.server.wm.ScreenshotTests$ScreenshotActivity" /> + <activity android:name="android.view.cts.surfacevalidator.CapturedActivity"/> + + <service android:name="android.view.cts.surfacevalidator.LocalMediaProjectionService" + android:foregroundServiceType="mediaProjection" + android:enabled="true"> + </service> </application> <instrumentation diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 9f7130e45483..c08387024818 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -75,7 +75,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.same; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; -import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT; import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM; @@ -1117,7 +1116,7 @@ public class DisplayContentTests extends WindowTestsBase { app.removeImmediately(); - assertNull(dc.getImeTarget(IME_TARGET_INPUT)); + assertNull(dc.getImeInputTarget()); assertNull(dc.computeImeControlTarget()); } @@ -1126,19 +1125,19 @@ public class DisplayContentTests extends WindowTestsBase { final DisplayContent dc = createNewDisplay(); dc.setRemoteInsetsController(createDisplayWindowInsetsController()); dc.setImeInputTarget(createWindow(null, TYPE_BASE_APPLICATION, "app")); - dc.setImeLayeringTarget(dc.getImeTarget(IME_TARGET_INPUT).getWindow()); - assertEquals(dc.getImeTarget(IME_TARGET_INPUT).getWindow(), dc.computeImeControlTarget()); + dc.setImeLayeringTarget(dc.getImeInputTarget().getWindowState()); + assertEquals(dc.getImeInputTarget().getWindowState(), dc.computeImeControlTarget()); } @Test public void testComputeImeControlTarget_splitscreen() throws Exception { final DisplayContent dc = createNewDisplay(); dc.setImeInputTarget(createWindow(null, TYPE_BASE_APPLICATION, "app")); - dc.getImeTarget(IME_TARGET_INPUT).getWindow().setWindowingMode( + dc.getImeInputTarget().getWindowState().setWindowingMode( WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW); - dc.setImeLayeringTarget(dc.getImeTarget(IME_TARGET_INPUT).getWindow()); + dc.setImeLayeringTarget(dc.getImeInputTarget().getWindowState()); dc.setRemoteInsetsController(createDisplayWindowInsetsController()); - assertNotEquals(dc.getImeTarget(IME_TARGET_INPUT).getWindow(), + assertNotEquals(dc.getImeInputTarget().getWindowState(), dc.computeImeControlTarget()); } @@ -1149,7 +1148,7 @@ public class DisplayContentTests extends WindowTestsBase { doReturn(false).when(mAppWindow.mActivityRecord).matchParentBounds(); mDisplayContent.setImeInputTarget(mAppWindow); mDisplayContent.setImeLayeringTarget( - mDisplayContent.getImeTarget(IME_TARGET_INPUT).getWindow()); + mDisplayContent.getImeInputTarget().getWindowState()); mDisplayContent.setRemoteInsetsController(createDisplayWindowInsetsController()); assertEquals(mAppWindow, mDisplayContent.computeImeControlTarget()); } @@ -1927,7 +1926,7 @@ public class DisplayContentTests extends WindowTestsBase { child1.removeImmediately(); verify(mDisplayContent).computeImeTarget(true); - assertNull(mDisplayContent.getImeTarget(IME_TARGET_INPUT)); + assertNull(mDisplayContent.getImeInputTarget()); verify(child1, never()).needsRelativeLayeringToIme(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index e3876150bf99..90a6918644fa 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -30,7 +30,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; -import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static org.junit.Assert.assertEquals; @@ -182,12 +181,13 @@ public class InsetsStateControllerTest extends WindowTestsBase { // Make IME and stay visible during the test. mImeWindow.setHasSurface(true); getController().getSourceProvider(ITYPE_IME).setWindowContainer(mImeWindow, null, null); - getController().onImeControlTargetChanged(mDisplayContent.getImeTarget(IME_TARGET_INPUT)); + getController().onImeControlTargetChanged( + mDisplayContent.getImeInputTarget().getWindowState()); final InsetsVisibilities requestedVisibilities = new InsetsVisibilities(); requestedVisibilities.setVisibility(ITYPE_IME, true); - mDisplayContent.getImeTarget(IME_TARGET_INPUT).getWindow() + mDisplayContent.getImeInputTarget().getWindowState() .setRequestedVisibilities(requestedVisibilities); - getController().onInsetsModified(mDisplayContent.getImeTarget(IME_TARGET_INPUT)); + getController().onInsetsModified(mDisplayContent.getImeInputTarget().getWindowState()); // Send our spy window (app) into the system so that we can detect the invocation. final WindowState win = createWindow(null, TYPE_APPLICATION, "app"); diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerContinuousTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerContinuousTest.java new file mode 100644 index 000000000000..1e3250080514 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerContinuousTest.java @@ -0,0 +1,66 @@ +/* + * 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.wm; + +import static android.server.wm.UiDeviceUtils.pressUnlockButton; +import static android.server.wm.UiDeviceUtils.pressWakeupButton; +import static android.server.wm.WindowManagerState.getLogicalDisplaySize; + +import android.app.KeyguardManager; +import android.os.PowerManager; +import android.view.SurfaceControl; +import android.view.cts.surfacevalidator.CapturedActivity; +import android.window.SurfaceSyncer; + +import androidx.test.rule.ActivityTestRule; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +import java.util.Objects; + +public class SurfaceSyncerContinuousTest { + @Rule + public TestName mName = new TestName(); + + @Rule + public ActivityTestRule<CapturedActivity> mActivityRule = + new ActivityTestRule<>(CapturedActivity.class); + + public CapturedActivity mCapturedActivity; + + @Before + public void setup() { + mCapturedActivity = mActivityRule.getActivity(); + mCapturedActivity.setLogicalDisplaySize(getLogicalDisplaySize()); + + final KeyguardManager km = mCapturedActivity.getSystemService(KeyguardManager.class); + if (km != null && km.isKeyguardLocked() || !Objects.requireNonNull( + mCapturedActivity.getSystemService(PowerManager.class)).isInteractive()) { + pressWakeupButton(); + pressUnlockButton(); + } + } + + @Test + public void testSurfaceViewSyncDuringResize() throws Throwable { + SurfaceSyncer.setTransactionFactory(SurfaceControl.Transaction::new); + mCapturedActivity.verifyTest(new SurfaceSyncerValidatorTestCase(), mName); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerTest.java new file mode 100644 index 000000000000..cc28ea6f55d2 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerTest.java @@ -0,0 +1,146 @@ +/* + * 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.wm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import android.platform.test.annotations.Presubmit; +import android.view.SurfaceControl; +import android.window.SurfaceSyncer; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +@SmallTest +@Presubmit +public class SurfaceSyncerTest { + private SurfaceSyncer mSurfaceSyncer; + + @Before + public void setup() { + mSurfaceSyncer = new SurfaceSyncer(); + SurfaceSyncer.setTransactionFactory(StubTransaction::new); + } + + @Test + public void testSyncOne() throws InterruptedException { + final CountDownLatch finishedLatch = new CountDownLatch(1); + int startSyncId = mSurfaceSyncer.setupSync(transaction -> finishedLatch.countDown()); + Syncable syncable = new Syncable(); + mSurfaceSyncer.addToSync(startSyncId, syncable); + mSurfaceSyncer.markSyncReady(startSyncId); + + syncable.onBufferReady(); + + finishedLatch.await(5, TimeUnit.SECONDS); + assertEquals(0, finishedLatch.getCount()); + } + + @Test + public void testSyncMultiple() throws InterruptedException { + final CountDownLatch finishedLatch = new CountDownLatch(1); + int startSyncId = mSurfaceSyncer.setupSync(transaction -> finishedLatch.countDown()); + Syncable syncable1 = new Syncable(); + Syncable syncable2 = new Syncable(); + Syncable syncable3 = new Syncable(); + + mSurfaceSyncer.addToSync(startSyncId, syncable1); + mSurfaceSyncer.addToSync(startSyncId, syncable2); + mSurfaceSyncer.addToSync(startSyncId, syncable3); + mSurfaceSyncer.markSyncReady(startSyncId); + + syncable1.onBufferReady(); + assertNotEquals(0, finishedLatch.getCount()); + + syncable3.onBufferReady(); + assertNotEquals(0, finishedLatch.getCount()); + + syncable2.onBufferReady(); + + finishedLatch.await(5, TimeUnit.SECONDS); + assertEquals(0, finishedLatch.getCount()); + } + + @Test + public void testInvalidSyncId() { + assertFalse(mSurfaceSyncer.addToSync(0, new Syncable())); + } + + @Test + public void testAddSyncWhenSyncComplete() throws InterruptedException { + final CountDownLatch finishedLatch = new CountDownLatch(1); + int startSyncId = mSurfaceSyncer.setupSync(transaction -> finishedLatch.countDown()); + + Syncable syncable1 = new Syncable(); + Syncable syncable2 = new Syncable(); + + assertTrue(mSurfaceSyncer.addToSync(startSyncId, syncable1)); + mSurfaceSyncer.markSyncReady(startSyncId); + // Adding to a sync that has been completed is also invalid since the sync id has been + // cleared. + assertFalse(mSurfaceSyncer.addToSync(startSyncId, syncable2)); + } + + @Test + public void testMultipleSyncSets() throws InterruptedException { + final CountDownLatch finishedLatch1 = new CountDownLatch(1); + final CountDownLatch finishedLatch2 = new CountDownLatch(1); + int startSyncId1 = mSurfaceSyncer.setupSync(transaction -> finishedLatch1.countDown()); + int startSyncId2 = mSurfaceSyncer.setupSync(transaction -> finishedLatch2.countDown()); + + Syncable syncable1 = new Syncable(); + Syncable syncable2 = new Syncable(); + + assertTrue(mSurfaceSyncer.addToSync(startSyncId1, syncable1)); + assertTrue(mSurfaceSyncer.addToSync(startSyncId2, syncable2)); + mSurfaceSyncer.markSyncReady(startSyncId1); + mSurfaceSyncer.markSyncReady(startSyncId2); + + syncable1.onBufferReady(); + + finishedLatch1.await(5, TimeUnit.SECONDS); + assertEquals(0, finishedLatch1.getCount()); + assertNotEquals(0, finishedLatch2.getCount()); + + syncable2.onBufferReady(); + + finishedLatch2.await(5, TimeUnit.SECONDS); + assertEquals(0, finishedLatch2.getCount()); + } + + private static class Syncable implements SurfaceSyncer.SyncTarget { + private SurfaceSyncer.SyncBufferCallback mSyncBufferCallback; + + @Override + public void onReadyToSync(SurfaceSyncer.SyncBufferCallback syncBufferCallback) { + mSyncBufferCallback = syncBufferCallback; + } + + void onBufferReady() { + SurfaceControl.Transaction t = new StubTransaction(); + mSyncBufferCallback.onBufferReady(t); + } + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerValidatorTestCase.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerValidatorTestCase.java new file mode 100644 index 000000000000..77a8615e20d6 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerValidatorTestCase.java @@ -0,0 +1,223 @@ +/* + * 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.wm; + +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.ViewGroup; +import android.view.cts.surfacevalidator.ISurfaceValidatorTestCase; +import android.view.cts.surfacevalidator.PixelChecker; +import android.widget.FrameLayout; +import android.window.SurfaceSyncer; + +import androidx.annotation.NonNull; + +/** + * A validator class that will create a SurfaceView and then update its size over and over. The code + * will request to sync the SurfaceView content with the main window and validate that there was + * never an empty area (black color). The test uses {@link SurfaceSyncer} class to gather the + * content it wants to synchronize. + */ +public class SurfaceSyncerValidatorTestCase implements ISurfaceValidatorTestCase { + private static final String TAG = "SurfaceSyncerValidatorTestCase"; + + private final Runnable mRunnable = new Runnable() { + @Override + public void run() { + updateSurfaceViewSize(); + mHandler.postDelayed(this, 100); + } + }; + + private Handler mHandler; + private SurfaceView mSurfaceView; + private boolean mLastExpanded = true; + private final SurfaceSyncer mSurfaceSyncer = new SurfaceSyncer(); + + private RenderingThread mRenderingThread; + private FrameLayout mParent; + + private int mLastSyncId = -1; + + final SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + final Canvas canvas = holder.lockCanvas(); + canvas.drawARGB(255, 100, 100, 100); + holder.unlockCanvasAndPost(canvas); + Log.d(TAG, "surfaceCreated"); + mRenderingThread = new RenderingThread(holder); + mRenderingThread.start(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, + int height) { + if (mLastSyncId >= 0) { + mSurfaceSyncer.addToSync(mLastSyncId, mSurfaceView, frameCallback -> + mRenderingThread.setFrameCallback(frameCallback)); + mSurfaceSyncer.markSyncReady(mLastSyncId); + mLastSyncId = -1; + } + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + mRenderingThread.stopRendering(); + } + }; + + @Override + public PixelChecker getChecker() { + return new PixelChecker(Color.BLACK) { + @Override + public boolean checkPixels(int matchingPixelCount, int width, int height) { + return matchingPixelCount == 0; + } + }; + } + + @Override + public void start(Context context, FrameLayout parent) { + mSurfaceView = new SurfaceView(context); + mSurfaceView.getHolder().addCallback(mCallback); + mParent = parent; + + FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(MATCH_PARENT, 600); + parent.addView(mSurfaceView, layoutParams); + mHandler = new Handler(Looper.getMainLooper()); + mHandler.post(mRunnable); + } + + @Override + public void end() { + mHandler.removeCallbacks(mRunnable); + } + + public void updateSurfaceViewSize() { + if (mRenderingThread == null || mLastSyncId >= 0 || !mRenderingThread.isReadyToSync()) { + return; + } + + Log.d(TAG, "updateSurfaceViewSize"); + + final int height; + if (mLastExpanded) { + height = 300; + } else { + height = 600; + } + mLastExpanded = !mLastExpanded; + + mRenderingThread.pauseRendering(); + mLastSyncId = mSurfaceSyncer.setupSync(() -> { }); + mSurfaceSyncer.addToSync(mLastSyncId, mParent); + + ViewGroup.LayoutParams svParams = mSurfaceView.getLayoutParams(); + svParams.height = height; + mSurfaceView.setLayoutParams(svParams); + } + + private static class RenderingThread extends HandlerThread { + private final SurfaceHolder mSurfaceHolder; + private SurfaceSyncer.SurfaceViewFrameCallback mFrameCallback; + private boolean mPauseRendering; + private boolean mComplete; + + int mColorValue = 0; + int mColorDelta = 10; + + @Override + public void run() { + try { + while (true) { + sleep(10); + synchronized (this) { + if (mComplete) { + break; + } + if (mPauseRendering) { + continue; + } + + if (mFrameCallback != null) { + Log.d(TAG, "onFrameStarted"); + mFrameCallback.onFrameStarted(); + } + + mColorValue += mColorDelta; + if (mColorValue > 245 || mColorValue < 10) { + mColorDelta *= -1; + } + + Canvas c = mSurfaceHolder.lockCanvas(); + if (c != null) { + c.drawRGB(255, mColorValue, 255 - mColorValue); + mSurfaceHolder.unlockCanvasAndPost(c); + } + + if (mFrameCallback != null) { + Log.d(TAG, "onFrameComplete"); + mFrameCallback.onFrameComplete(); + } + + mFrameCallback = null; + } + } + } catch (InterruptedException e) { + } + } + + RenderingThread(SurfaceHolder holder) { + super("RenderingThread"); + mSurfaceHolder = holder; + } + + public void pauseRendering() { + synchronized (this) { + mPauseRendering = true; + } + } + + private boolean isReadyToSync() { + synchronized (this) { + return mFrameCallback == null; + } + } + public void setFrameCallback(SurfaceSyncer.SurfaceViewFrameCallback frameCallback) { + synchronized (this) { + mFrameCallback = frameCallback; + mPauseRendering = false; + } + } + + public void stopRendering() { + synchronized (this) { + mComplete = true; + } + } + } +} diff --git a/services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java b/services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java new file mode 100644 index 000000000000..bfc17713b6a8 --- /dev/null +++ b/services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java @@ -0,0 +1,221 @@ +/* + * 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.usage; + +import static android.app.ActivityManager.procStateToString; + +import static com.android.server.usage.BroadcastResponseStatsTracker.NOTIFICATION_EVENT_TYPE_CANCELLED; +import static com.android.server.usage.BroadcastResponseStatsTracker.NOTIFICATION_EVENT_TYPE_POSTED; +import static com.android.server.usage.BroadcastResponseStatsTracker.NOTIFICATION_EVENT_TYPE_UPDATED; +import static com.android.server.usage.BroadcastResponseStatsTracker.TAG; +import static com.android.server.usage.UsageStatsService.DEBUG_RESPONSE_STATS; + +import android.annotation.ElapsedRealtimeLong; +import android.annotation.NonNull; +import android.annotation.UserIdInt; +import android.app.ActivityManager; +import android.app.ActivityManager.ProcessState; +import android.os.UserHandle; +import android.text.TextUtils; +import android.util.Slog; +import android.util.TimeUtils; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.RingBuffer; +import com.android.server.usage.BroadcastResponseStatsTracker.NotificationEventType; + +public class BroadcastResponseStatsLogger { + + private static final int MAX_LOG_SIZE = + ActivityManager.isLowRamDeviceStatic() ? 20 : 50; + + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private final LogBuffer mBroadcastEventsBuffer = new LogBuffer( + BroadcastEvent.class, MAX_LOG_SIZE); + @GuardedBy("mLock") + private final LogBuffer mNotificationEventsBuffer = new LogBuffer( + NotificationEvent.class, MAX_LOG_SIZE); + + void logBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage, + UserHandle targetUser, long idForResponseEvent, + @ElapsedRealtimeLong long timeStampMs, @ProcessState int targetUidProcessState) { + synchronized (mLock) { + if (DEBUG_RESPONSE_STATS) { + Slog.d(TAG, getBroadcastDispatchEventLog(sourceUid, targetPackage, + targetUser.getIdentifier(), idForResponseEvent, timeStampMs, + targetUidProcessState)); + } + mBroadcastEventsBuffer.logBroadcastDispatchEvent(sourceUid, targetPackage, + targetUser, idForResponseEvent, timeStampMs, targetUidProcessState); + } + } + + void logNotificationEvent(@NotificationEventType int event, + @NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) { + synchronized (mLock) { + if (DEBUG_RESPONSE_STATS) { + Slog.d(TAG, getNotificationEventLog(event, packageName, user.getIdentifier(), + timestampMs)); + } + mNotificationEventsBuffer.logNotificationEvent(event, packageName, user, timestampMs); + } + } + + void dumpLogs(IndentingPrintWriter ipw) { + synchronized (mLock) { + ipw.println("Broadcast events (most recent first):"); + ipw.increaseIndent(); + mBroadcastEventsBuffer.reverseDump(ipw); + ipw.decreaseIndent(); + + ipw.println(); + ipw.println("Notification events (most recent first):"); + ipw.increaseIndent(); + mNotificationEventsBuffer.reverseDump(ipw); + ipw.decreaseIndent(); + } + } + + private static final class LogBuffer<T extends Data> extends RingBuffer<T> { + + LogBuffer(Class<T> classType, int capacity) { + super(classType, capacity); + } + + void logBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage, + UserHandle targetUser, long idForResponseEvent, + @ElapsedRealtimeLong long timeStampMs, @ProcessState int targetUidProcessState) { + final Data data = getNextSlot(); + if (data == null) return; + + data.reset(); + final BroadcastEvent event = (BroadcastEvent) data; + event.sourceUid = sourceUid; + event.targetUserId = targetUser.getIdentifier(); + event.targetUidProcessState = targetUidProcessState; + event.targetPackage = targetPackage; + event.idForResponseEvent = idForResponseEvent; + event.timestampMs = timeStampMs; + } + + void logNotificationEvent(@NotificationEventType int type, + @NonNull String packageName, UserHandle user, + @ElapsedRealtimeLong long timestampMs) { + final Data data = getNextSlot(); + if (data == null) return; + + data.reset(); + final NotificationEvent event = (NotificationEvent) data; + event.type = type; + event.packageName = packageName; + event.userId = user.getIdentifier(); + event.timestampMs = timestampMs; + } + + public void reverseDump(IndentingPrintWriter pw) { + final Data[] allData = toArray(); + for (int i = allData.length - 1; i >= 0; --i) { + if (allData[i] == null) { + continue; + } + pw.println(getContent(allData[i])); + } + } + + @NonNull + public String getContent(Data data) { + return data.toString(); + } + } + + @NonNull + private static String getBroadcastDispatchEventLog(int sourceUid, @NonNull String targetPackage, + @UserIdInt int targetUserId, long idForResponseEvent, + @ElapsedRealtimeLong long timestampMs, @ProcessState int targetUidProcState) { + return TextUtils.formatSimple( + "broadcast:%s; srcUid=%d, tgtPkg=%s, tgtUsr=%d, id=%d, state=%s", + TimeUtils.formatDuration(timestampMs), sourceUid, targetPackage, targetUserId, + idForResponseEvent, procStateToString(targetUidProcState)); + } + + @NonNull + private static String getNotificationEventLog(@NotificationEventType int event, + @NonNull String packageName, @UserIdInt int userId, + @ElapsedRealtimeLong long timestampMs) { + return TextUtils.formatSimple("notification:%s; event=<%s>, pkg=%s, usr=%d", + TimeUtils.formatDuration(timestampMs), notificationEventToString(event), + packageName, userId); + } + + @NonNull + private static String notificationEventToString(@NotificationEventType int event) { + switch (event) { + case NOTIFICATION_EVENT_TYPE_POSTED: + return "posted"; + case NOTIFICATION_EVENT_TYPE_UPDATED: + return "updated"; + case NOTIFICATION_EVENT_TYPE_CANCELLED: + return "cancelled"; + default: + return String.valueOf(event); + } + } + + public static final class BroadcastEvent implements Data { + public int sourceUid; + public int targetUserId; + public int targetUidProcessState; + public String targetPackage; + public long idForResponseEvent; + public long timestampMs; + + @Override + public void reset() { + targetPackage = null; + } + + @Override + public String toString() { + return getBroadcastDispatchEventLog(sourceUid, targetPackage, targetUserId, + idForResponseEvent, timestampMs, targetUidProcessState); + } + } + + public static final class NotificationEvent implements Data { + public int type; + public String packageName; + public int userId; + public long timestampMs; + + @Override + public void reset() { + packageName = null; + } + + @Override + public String toString() { + return getNotificationEventLog(type, packageName, userId, timestampMs); + } + } + + public interface Data { + void reset(); + } +} diff --git a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java index ab8f69b121a0..76d2fe7917fc 100644 --- a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java +++ b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java @@ -16,10 +16,6 @@ package com.android.server.usage; -import static android.app.ActivityManager.procStateToString; - -import static com.android.server.usage.UsageStatsService.DEBUG_RESPONSE_STATS; - import android.annotation.ElapsedRealtimeLong; import android.annotation.IntDef; import android.annotation.IntRange; @@ -29,11 +25,9 @@ import android.annotation.UserIdInt; import android.app.ActivityManager.ProcessState; import android.app.usage.BroadcastResponseStats; import android.os.UserHandle; -import android.text.TextUtils; import android.util.LongSparseArray; import android.util.Slog; import android.util.SparseArray; -import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; @@ -44,19 +38,19 @@ import java.util.ArrayList; import java.util.List; class BroadcastResponseStatsTracker { - private static final String TAG = "ResponseStatsTracker"; + static final String TAG = "ResponseStatsTracker"; @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"NOTIFICATION_EVENT"}, value = { - NOTIFICATION_EVENT_POSTED, - NOTIFICATION_EVENT_UPDATED, - NOTIFICATION_EVENT_CANCELLED + @IntDef(prefix = {"NOTIFICATION_EVENT_TYPE_"}, value = { + NOTIFICATION_EVENT_TYPE_POSTED, + NOTIFICATION_EVENT_TYPE_UPDATED, + NOTIFICATION_EVENT_TYPE_CANCELLED }) - public @interface NotificationEvent {} + public @interface NotificationEventType {} - private static final int NOTIFICATION_EVENT_POSTED = 0; - private static final int NOTIFICATION_EVENT_UPDATED = 1; - private static final int NOTIFICATION_EVENT_CANCELLED = 2; + static final int NOTIFICATION_EVENT_TYPE_POSTED = 0; + static final int NOTIFICATION_EVENT_TYPE_UPDATED = 1; + static final int NOTIFICATION_EVENT_TYPE_CANCELLED = 2; private final Object mLock = new Object(); @@ -76,21 +70,19 @@ class BroadcastResponseStatsTracker { new SparseArray<>(); private AppStandbyInternal mAppStandby; + private BroadcastResponseStatsLogger mLogger; BroadcastResponseStatsTracker(@NonNull AppStandbyInternal appStandby) { mAppStandby = appStandby; + mLogger = new BroadcastResponseStatsLogger(); } // TODO (206518114): Move all callbacks handling to a handler thread. void reportBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage, UserHandle targetUser, long idForResponseEvent, @ElapsedRealtimeLong long timestampMs, @ProcessState int targetUidProcState) { - if (DEBUG_RESPONSE_STATS) { - Slog.d(TAG, TextUtils.formatSimple("reportBroadcastDispatchEvent; " - + "srcUid=%d, tgtPkg=%s, tgtUsr=%d, id=%d, ts=%s, state=%s", - sourceUid, targetPackage, targetUser, idForResponseEvent, - TimeUtils.formatDuration(timestampMs), procStateToString(targetUidProcState))); - } + mLogger.logBroadcastDispatchEvent(sourceUid, targetPackage, targetUser, + idForResponseEvent, timestampMs, targetUidProcState); if (targetUidProcState <= mAppStandby.getBroadcastResponseFgThresholdState()) { // No need to track the broadcast response state while the target app is // in the foreground. @@ -110,29 +102,23 @@ class BroadcastResponseStatsTracker { void reportNotificationPosted(@NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) { - reportNotificationEvent(NOTIFICATION_EVENT_POSTED, packageName, user, timestampMs); + reportNotificationEvent(NOTIFICATION_EVENT_TYPE_POSTED, packageName, user, timestampMs); } void reportNotificationUpdated(@NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) { - reportNotificationEvent(NOTIFICATION_EVENT_UPDATED, packageName, user, timestampMs); + reportNotificationEvent(NOTIFICATION_EVENT_TYPE_UPDATED, packageName, user, timestampMs); } void reportNotificationCancelled(@NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) { - reportNotificationEvent(NOTIFICATION_EVENT_CANCELLED, packageName, user, timestampMs); + reportNotificationEvent(NOTIFICATION_EVENT_TYPE_CANCELLED, packageName, user, timestampMs); } - private void reportNotificationEvent(@NotificationEvent int event, + private void reportNotificationEvent(@NotificationEventType int event, @NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) { - if (DEBUG_RESPONSE_STATS) { - Slog.d(TAG, TextUtils.formatSimple( - "reportNotificationEvent; event=<%s>, pkg=%s, usr=%d, ts=%s", - notificationEventToString(event), packageName, user.getIdentifier(), - TimeUtils.formatDuration(timestampMs))); - } - // TODO (206518114): Store last N events to dump for debugging purposes. + mLogger.logNotificationEvent(event, packageName, user, timestampMs); synchronized (mLock) { final LongSparseArray<BroadcastEvent> broadcastEvents = getBroadcastEventsLocked(packageName, user); @@ -157,13 +143,13 @@ class BroadcastResponseStatsTracker { continue; } switch (event) { - case NOTIFICATION_EVENT_POSTED: + case NOTIFICATION_EVENT_TYPE_POSTED: responseStats.incrementNotificationsPostedCount(1); break; - case NOTIFICATION_EVENT_UPDATED: + case NOTIFICATION_EVENT_TYPE_UPDATED: responseStats.incrementNotificationsUpdatedCount(1); break; - case NOTIFICATION_EVENT_CANCELLED: + case NOTIFICATION_EVENT_TYPE_CANCELLED: responseStats.incrementNotificationsCancelledCount(1); break; default: @@ -329,20 +315,6 @@ class BroadcastResponseStatsTracker { return userResponseStats.getOrCreateBroadcastResponseStats(broadcastEvent); } - @NonNull - private String notificationEventToString(@NotificationEvent int event) { - switch (event) { - case NOTIFICATION_EVENT_POSTED: - return "posted"; - case NOTIFICATION_EVENT_UPDATED: - return "updated"; - case NOTIFICATION_EVENT_CANCELLED: - return "cancelled"; - default: - return String.valueOf(event); - } - } - void dump(@NonNull IndentingPrintWriter ipw) { ipw.println("Broadcast response stats:"); ipw.increaseIndent(); @@ -351,6 +323,8 @@ class BroadcastResponseStatsTracker { dumpBroadcastEventsLocked(ipw); ipw.println(); dumpResponseStatsLocked(ipw); + ipw.println(); + mLogger.dumpLogs(ipw); } ipw.decreaseIndent(); diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 7f70301735d9..1999cfc706b4 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -2187,7 +2187,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser * @param uid Uid of the caller */ public ParcelFileDescriptor openAccessory(UsbAccessory accessory, - UsbUserPermissionManager permissions, int uid) { + UsbUserPermissionManager permissions, int pid, int uid) { UsbAccessory currentAccessory = mHandler.getCurrentAccessory(); if (currentAccessory == null) { throw new IllegalArgumentException("no accessory attached"); @@ -2198,7 +2198,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser + currentAccessory; throw new IllegalArgumentException(error); } - permissions.checkPermission(accessory, uid); + permissions.checkPermission(accessory, pid, uid); return nativeOpenAccessory(); } diff --git a/services/usb/java/com/android/server/usb/UsbSerialReader.java b/services/usb/java/com/android/server/usb/UsbSerialReader.java index f241e65ba755..9dda0e778394 100644 --- a/services/usb/java/com/android/server/usb/UsbSerialReader.java +++ b/services/usb/java/com/android/server/usb/UsbSerialReader.java @@ -98,7 +98,7 @@ class UsbSerialReader extends IUsbSerialReader.Stub { .checkPermission((UsbDevice) mDevice, packageName, pid, uid); } else { mPermissionManager.getPermissionsForUser(userId) - .checkPermission((UsbAccessory) mDevice, uid); + .checkPermission((UsbAccessory) mDevice, pid, uid); } } } diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java index c0ecf58087fa..e06ab022688f 100644 --- a/services/usb/java/com/android/server/usb/UsbService.java +++ b/services/usb/java/com/android/server/usb/UsbService.java @@ -321,6 +321,7 @@ public class UsbService extends IUsbManager.Stub { public ParcelFileDescriptor openAccessory(UsbAccessory accessory) { if (mDeviceManager != null) { int uid = Binder.getCallingUid(); + int pid = Binder.getCallingPid(); int user = UserHandle.getUserId(uid); final long ident = clearCallingIdentity(); @@ -328,7 +329,7 @@ public class UsbService extends IUsbManager.Stub { synchronized (mLock) { if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) { return mDeviceManager.openAccessory(accessory, getPermissionsForUser(user), - uid); + pid, uid); } else { Slog.w(TAG, "Cannot open " + accessory + " for user " + user + " as user is not active."); @@ -505,11 +506,12 @@ public class UsbService extends IUsbManager.Stub { @Override public boolean hasAccessoryPermission(UsbAccessory accessory) { final int uid = Binder.getCallingUid(); + final int pid = Binder.getCallingPid(); final int userId = UserHandle.getUserId(uid); final long token = Binder.clearCallingIdentity(); try { - return getPermissionsForUser(userId).hasPermission(accessory, uid); + return getPermissionsForUser(userId).hasPermission(accessory, pid, uid); } finally { Binder.restoreCallingIdentity(token); } @@ -533,11 +535,12 @@ public class UsbService extends IUsbManager.Stub { public void requestAccessoryPermission( UsbAccessory accessory, String packageName, PendingIntent pi) { final int uid = Binder.getCallingUid(); + final int pid = Binder.getCallingPid(); final int userId = UserHandle.getUserId(uid); final long token = Binder.clearCallingIdentity(); try { - getPermissionsForUser(userId).requestPermission(accessory, packageName, pi, uid); + getPermissionsForUser(userId).requestPermission(accessory, packageName, pi, pid, uid); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java index 286cff90daab..dd5f153b2518 100644 --- a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java +++ b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java @@ -246,9 +246,13 @@ class UsbUserPermissionManager { * @param uid to check permission for * @return {@code true} if caller has permssion */ - boolean hasPermission(@NonNull UsbAccessory accessory, int uid) { + boolean hasPermission(@NonNull UsbAccessory accessory, int pid, int uid) { synchronized (mLock) { - if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) { + if (uid == Process.SYSTEM_UID + || mDisablePermissionDialogs + || mContext.checkPermission( + android.Manifest.permission.MANAGE_USB, pid, uid) + == android.content.pm.PackageManager.PERMISSION_GRANTED) { return true; } AccessoryFilter filter = new AccessoryFilter(accessory); @@ -675,8 +679,8 @@ class UsbUserPermissionManager { } } - public void checkPermission(UsbAccessory accessory, int uid) { - if (!hasPermission(accessory, uid)) { + public void checkPermission(UsbAccessory accessory, int pid, int uid) { + if (!hasPermission(accessory, pid, uid)) { throw new SecurityException("User has not given " + uid + " permission to accessory " + accessory); } @@ -745,9 +749,9 @@ class UsbUserPermissionManager { } public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi, - int uid) { + int pid, int uid) { // respond immediately if permission has already been granted - if (hasPermission(accessory, uid)) { + if (hasPermission(accessory, pid, uid)) { Intent intent = new Intent(); intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true); diff --git a/telephony/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java index 8d9252019538..7129a27c3cd6 100644 --- a/telephony/java/android/service/euicc/EuiccService.java +++ b/telephony/java/android/service/euicc/EuiccService.java @@ -29,7 +29,6 @@ import android.content.Intent; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; -import android.telephony.TelephonyManager; import android.telephony.euicc.DownloadableSubscription; import android.telephony.euicc.EuiccInfo; import android.telephony.euicc.EuiccManager; @@ -744,18 +743,16 @@ public abstract class EuiccService extends Service { public void run() { DownloadSubscriptionResult result; try { - result = - EuiccService.this.onDownloadSubscription( - slotId, subscription, switchAfterDownload, forceDeactivateSim, - resolvedBundle); + result = EuiccService.this.onDownloadSubscription( + slotId, portIndex, subscription, switchAfterDownload, + forceDeactivateSim, resolvedBundle); } catch (AbstractMethodError e) { - Log.w(TAG, "The new onDownloadSubscription(int, " + Log.w(TAG, "The new onDownloadSubscription(int, int, " + "DownloadableSubscription, boolean, boolean, Bundle) is not " + "implemented. Fall back to the old one.", e); - int resultCode = EuiccService.this.onDownloadSubscription( - slotId, subscription, switchAfterDownload, forceDeactivateSim); - result = new DownloadSubscriptionResult(resultCode, - 0 /* resolvableErrors */, TelephonyManager.UNSUPPORTED_CARD_ID); + result = EuiccService.this.onDownloadSubscription( + slotId, subscription, switchAfterDownload, + forceDeactivateSim, resolvedBundle); } try { callback.onComplete(result); diff --git a/tests/AttestationVerificationTest/Android.bp b/tests/AttestationVerificationTest/Android.bp index a4741eedaac0..b98f8cb0c21d 100644 --- a/tests/AttestationVerificationTest/Android.bp +++ b/tests/AttestationVerificationTest/Android.bp @@ -40,5 +40,6 @@ android_test { "androidx.test.rules", "androidx.test.ext.junit", "platform-test-annotations", + "services.core", ], } diff --git a/tests/AttestationVerificationTest/AndroidManifest.xml b/tests/AttestationVerificationTest/AndroidManifest.xml index c42bde9dca3a..37321ad80b0f 100755 --- a/tests/AttestationVerificationTest/AndroidManifest.xml +++ b/tests/AttestationVerificationTest/AndroidManifest.xml @@ -24,6 +24,7 @@ <application> <uses-library android:name="android.test.runner"/> <activity android:name=".SystemAttestationVerificationTest$TestActivity" /> + <activity android:name=".PeerDeviceSystemAttestationVerificationTest$TestActivity" /> </application> <!-- self-instrumenting test package. --> diff --git a/tests/AttestationVerificationTest/assets/test_attestation_with_root_certs.pem b/tests/AttestationVerificationTest/assets/test_attestation_with_root_certs.pem new file mode 100644 index 000000000000..e29ff487806e --- /dev/null +++ b/tests/AttestationVerificationTest/assets/test_attestation_with_root_certs.pem @@ -0,0 +1,81 @@ +-----BEGIN CERTIFICATE----- +MIICkjCCAjmgAwIBAgIBATAKBggqhkjOPQQDAjA5MQwwCgYDVQQMDANURUUxKTAn +BgNVBAUTIDg2ZTQ0MjRhMjY2NDlhZDcyZWZhNWM0MWEwM2IyN2QxMCAXDTcwMDEw +MTAwMDAwMFoYDzIxMDYwMjA3MDYyODE1WjAfMR0wGwYDVQQDDBRBbmRyb2lkIEtl +eXN0b3JlIEtleTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABIlTwcvhe+DLV45X +RCTO7HoN20Ib7IbCEhV5+YdMiYOp/0AdKk8oYvsri1XODeC4zcoPfHNdQGt/68i0 +ADbilJmjggFIMIIBRDAOBgNVHQ8BAf8EBAMCB4AwggEwBgorBgEEAdZ5AgERBIIB +IDCCARwCAQMKAQECAQQKAQEECXBsYXllcjQ1NgQAMFe/hT0IAgYBfvkgVei/hUVH +BEUwQzEdMBsEFmNvbS5nb29nbGUuYXR0ZXN0YXRpb24CAQExIgQgOqyVXRJUdAGY +/XVx8y/uRPiebqlyELt1EpqIz29h5tUwgaehCDEGAgECAgEDogMCAQOjBAICAQCl +CDEGAgEEAgEGqgMCAQG/g3cCBQC/hT4DAgEAv4VATDBKBCCEZx8qY8Ys0HC2TqPq +74eYPzh5L/agxD7Bn7zVBQHoNAEB/woBAAQguJwoDfWBjRaedzQ6TJPFJJKs+ytr ++8Vu2CSmqifFBHW/hUEFAgMB1MC/hUIFAgMDFdm/hU4GAgQBNIjJv4VPBgIEATSI +yTAKBggqhkjOPQQDAgNHADBEAiBdGxfMEx59k5+zo+hV3Q9kgjbGi0zU3WH355P5 +JZttBwIgY4FZsSreUJL8RY3JvfvD8BRw8GuXcB1OQ600hwaYYC4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB8zCCAXqgAwIBAgIRAOuuukN0OHbNQvKngECkewEwCgYIKoZIzj0EAwIwOTEM +MAoGA1UEDAwDVEVFMSkwJwYDVQQFEyA3MDkxMmRmNDYxMDRmYWFlOTQ3ODY0ZTU4 +MDRmMWY4ZDAeFw0yMDA5MjgyMDI3NTZaFw0zMDA5MjYyMDI3NTZaMDkxDDAKBgNV +BAwMA1RFRTEpMCcGA1UEBRMgODZlNDQyNGEyNjY0OWFkNzJlZmE1YzQxYTAzYjI3 +ZDEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT3Mjl05ewv6G8zAR4fXJy2iadU +yK7rNvzlECy2+nhEieL8BFXDvo0tx5fYs8qr67j/KvluFBfp2r9s+ckWz3Kzo2Mw +YTAdBgNVHQ4EFgQUsVKBzAs1lMXAauQ3mGAJZJqK5tAwHwYDVR0jBBgwFoAUEsQA +i8d2oLULSi5Ix4BTGGbvUEkwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AgQwCgYIKoZIzj0EAwIDZwAwZAIwfFziBCwuM1thLUSUNI61Xx/vnDnNkSv/aX5D +yLjxbLlgnFSzIrc+6vf6h6L/+TjYAjAq6h9GKtMn4R0286MoqYqzp/rHn6JD2sqH +iM8KZ0oA+Ut242EcmGjAoNfGZGZGddQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDkzCCAXugAwIBAgIQNTAX5z3CBac6nD3hQiMDcDANBgkqhkiG9w0BAQsFADAb +MRkwFwYDVQQFExBmOTIwMDllODUzYjZiMDQ1MB4XDTIwMDkyODIwMjUwMloXDTMw +MDkyNjIwMjUwMlowOTEMMAoGA1UEDAwDVEVFMSkwJwYDVQQFEyA3MDkxMmRmNDYx +MDRmYWFlOTQ3ODY0ZTU4MDRmMWY4ZDB2MBAGByqGSM49AgEGBSuBBAAiA2IABA/7 +xZFlFtTjdy2B3p7E+FsrBjyhBSqY4a9FywawXMJRSja3HAK36ruzJjWlEkD+D0vq +HI2joY39FHmWoZWwm2cq9gOleFGYOSCpMr4ib7xtq/6nefvKTP5rutxudF97t6Nj +MGEwHQYDVR0OBBYEFBLEAIvHdqC1C0ouSMeAUxhm71BJMB8GA1UdIwQYMBaAFDZh +4QB8iAUJUYtEbEf/GkzJ6k8SMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgIEMA0GCSqGSIb3DQEBCwUAA4ICAQAaMONDQxJz3PRn9gHQW5KP+TIoBPJZyGa1 +QFuEBcMDTtIxBxEh5Pj3ivPBc76PrdYu5U47Ve5YYCPsTpUTj7dOxbzGSZjfjvHF +fNwy24g1Lah2iAdQRVErhWKBlpnQhBnnRrrNmTTmzhl8NvSExqAPP746dqwm1kQ7 +YesC5yoEAHpxamhlZpIKAjSxSZeHWace2qV00M8qWd/7lIpqttJjFFrhCjzR0dtr +oIIpC5EtmqIWdLeg6yZjJkX+Cjv4F8mRfBtwuNuxFsfALQ3D5l8WKw3iwPebmCy1 +kEby8Eoq88FxzXQp/XgAaljlrKXyuxptrc1noRuob4g42Oh6wetueYRSCtO6Bkym +0UMnld/kG77aeiHOMVVb86wrhNuAGir1vgDGOBsclITVyuu9ka0YVQjjDm3phTpd +O8JV16gbei2Phn+FfRV1MSDsZo/wu0i2KVzgs27bfJocMHXv+GzvwfefYgMJ/rYq +Bg27lpsWzmFEPv2cyhA5PwwbG8ceswa3RZE/2eS9o7STkz93jr/KsKLcMBY6cX2C +q4CBJByKFJtVANOVj+neFNxc2sQgeTT33yYNKbe4b5bm7Ki1FbrhFVckpzUGDnKs +gL+AxvALWOoryDGwNbJiW8PRiD3HHByiMvSEQ7e7BSc2KjbsaWbCfYZAMZJEhEsc +P1l8lcUVuA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFHDCCAwSgAwIBAgIJANUP8luj8tazMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV +BAUTEGY5MjAwOWU4NTNiNmIwNDUwHhcNMTkxMTIyMjAzNzU4WhcNMzQxMTE4MjAz +NzU4WjAbMRkwFwYDVQQFExBmOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHsK7Qui8xUFmOr75gvMsd/dTEDDJdS +Sxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfdnJLmN0pTy/4lj4/7 +tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL/ggj +nar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGq +C4FSYa04T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQ +oVJYnFPlXTcHYvASLu+RhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+O +JtvsBslHZvPBKCOdT0MS+tgSOIfga+z1Z1g7+DVagf7quvmag8jfPioyKvxnK/Eg +sTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgpZrt3i5MIlCaY504LzSRi +igHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6tUXHI/+M +RPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9E +aDK8Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5Um +AGMCAwEAAaNjMGEwHQYDVR0OBBYEFDZh4QB8iAUJUYtEbEf/GkzJ6k8SMB8GA1Ud +IwQYMBaAFDZh4QB8iAUJUYtEbEf/GkzJ6k8SMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgIEMA0GCSqGSIb3DQEBCwUAA4ICAQBOMaBc8oumXb2voc7XCWnu +XKhBBK3e2KMGz39t7lA3XXRe2ZLLAkLM5y3J7tURkf5a1SutfdOyXAmeE6SRo83U +h6WszodmMkxK5GM4JGrnt4pBisu5igXEydaW7qq2CdC6DOGjG+mEkN8/TA6p3cno +L/sPyz6evdjLlSeJ8rFBH6xWyIZCbrcpYEJzXaUOEaxxXxgYz5/cTiVKN2M1G2ok +QBUIYSY6bjEL4aUN5cfo7ogP3UvliEo3Eo0YgwuzR2v0KR6C1cZqZJSTnghIC/vA +D32KdNQ+c3N+vl2OTsUVMC1GiWkngNx1OO1+kXW+YTnnTUOtOIswUP/Vqd5SYgAI +mMAfY8U9/iIgkQj6T2W6FsScy94IN9fFhE1UtzmLoBIuUFsVXJMTz+Jucth+IqoW +Fua9v1R93/k98p41pjtFX+H8DslVgfP097vju4KDlqN64xV1grw3ZLl4CiOe/A91 +oeLm2UHOq6wn3esB4r2EIQKb6jTVGu5sYCcdWpXr0AUVqcABPdgL+H7qJguBw09o +jm6xNIrw2OocrDKsudk/okr/AwqEyPKw9WnMlQgLIKw1rODG2NvU9oR3GVGdMkUB +ZutL8VuFkERQGt6vQ2OCw0sV47VMkuYbacK/xyZFiRcrPJPb41zgbQj9XAEyLKCH +ex0SdDrx+tWUDqG8At2JHA== +-----END CERTIFICATE----- diff --git a/tests/AttestationVerificationTest/assets/test_attestation_wrong_root_certs.pem b/tests/AttestationVerificationTest/assets/test_attestation_wrong_root_certs.pem new file mode 100644 index 000000000000..3d6410af042a --- /dev/null +++ b/tests/AttestationVerificationTest/assets/test_attestation_wrong_root_certs.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIGCDCCBHCgAwIBAgIBATANBgkqhkiG9w0BAQsFADApMRkwFwYDVQQFExAyZGM1OGIyZDFhMjQx +MzI2MQwwCgYDVQQMDANURUUwIBcNNzAwMTAxMDAwMDAwWhgPMjEwNjAyMDcwNjI4MTVaMB8xHTAb +BgNVBAMMFEFuZHJvaWQgS2V5c3RvcmUgS2V5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEApNVcnyN40MANMbbo2nMGNq2NNysDSjfLm0W3i6wPKf0ffCYkhWM4dCmQKKf50uAZTBeTit4c +NwXeZn3qellMlOsIN3Qc384rfN/8cikrRvUAgibz0Jy7STykjwa7x6tKwqITxbO8HqAhKo8/BQXU +xzrOdIg5ciy+UM7Vgh7a7ogen0KL2iGgrsalb1ti7Vlzb6vIJ4WzIC3TGD2sCkoPahghwqFDZZCo +/FzaLoNY0jAUX2mL+kf8aUaoxz7xA9FTvgara+1pLBR1s4c8xPS2HdZipcVXWfey0wujv1VAKs4+ +tXjKlHkYBHBBceEjxUtEmrapSQEdpHPv7Xh9Uanq4QIDAQABo4ICwTCCAr0wDgYDVR0PAQH/BAQD +AgeAMIICqQYKKwYBBAHWeQIBEQSCApkwggKVAgEDCgEBAgEECgEBBANhYmMEADCCAc2/hT0IAgYB +ZOYGEYe/hUWCAbsEggG3MIIBszGCAYswDAQHYW5kcm9pZAIBHTAZBBRjb20uYW5kcm9pZC5rZXlj +aGFpbgIBHTAZBBRjb20uYW5kcm9pZC5zZXR0aW5ncwIBHTAZBBRjb20ucXRpLmRpYWdzZXJ2aWNl +cwIBHTAaBBVjb20uYW5kcm9pZC5keW5zeXN0ZW0CAR0wHQQYY29tLmFuZHJvaWQuaW5wdXRkZXZp +Y2VzAgEdMB8EGmNvbS5hbmRyb2lkLmxvY2FsdHJhbnNwb3J0AgEdMB8EGmNvbS5hbmRyb2lkLmxv +Y2F0aW9uLmZ1c2VkAgEdMB8EGmNvbS5hbmRyb2lkLnNlcnZlci50ZWxlY29tAgEdMCAEG2NvbS5h +bmRyb2lkLndhbGxwYXBlcmJhY2t1cAIBHTAhBBxjb20uZ29vZ2xlLlNTUmVzdGFydERldGVjdG9y +AgEdMCIEHWNvbS5nb29nbGUuYW5kcm9pZC5oaWRkZW5tZW51AgEBMCMEHmNvbS5hbmRyb2lkLnBy +b3ZpZGVycy5zZXR0aW5ncwIBHTEiBCAwGqPLCBE0UBxF8UIqvGbCQiT9Xe1f3I8X5pcXb9hmqjCB +rqEIMQYCAQICAQOiAwIBAaMEAgIIAKUFMQMCAQSmCDEGAgEDAgEFv4FIBQIDAQABv4N3AgUAv4U+ +AwIBAL+FQEwwSgQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQAKAQIEIHKNsSdP +HxzxVx3kOAsEilVKxKOA529TVQg1KQhKk3gBv4VBAwIBAL+FQgUCAwMUs7+FTgUCAwMUs7+FTwUC +AwMUszANBgkqhkiG9w0BAQsFAAOCAYEAJMIuzdNUdfrE6sIdmsnMn/scSG2odbphj8FkX9JGdF2S +OT599HuDY9qhvkru2Dza4sLKK3f4ViBhuR9lpfeprKvstxbtBO7jkLYfVn0ZRzHRHVEyiW5IVKh+ +qOXVJ9S1lMShOTlsaYJytLKIlcrRAZBEXZiNbzTuVh1CH6X9Ni1dog14snm+lcOeORdL9fht2CHa +u/caRnpWiZbjoAoJp0O89uBrRkXPpln51+3jPY6AFny30grNAvKguauDcPPhNV1yR+ylSsQi2gm3 +Rs4pgtlxFLMfZLgT0cbkl+9zk/QUqlpBP8ftUBsOI0ARr8xhFN3cvq9kXGLtJ9hEP9PRaflAFREk +DK3IBIbVcAFZBFoAQOdE9zy0+F5bQrznPGaZg4Dzhcx33qMDUTgHtWoy+k3ePGQMEtmoTTLgQywW +OIkXEoFqqGi9GKJXUT1KYi5NsigaYqu7FoN4Qsvs61pMUEfZSPP2AFwkA8uNFbmb9uxcxaGHCA8i +3i9VM6yOLIrP +-----END CERTIFICATE----- diff --git a/tests/AttestationVerificationTest/assets/test_no_attestation_ext_certs.pem b/tests/AttestationVerificationTest/assets/test_no_attestation_ext_certs.pem new file mode 100644 index 000000000000..6d261fae47cf --- /dev/null +++ b/tests/AttestationVerificationTest/assets/test_no_attestation_ext_certs.pem @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFoDCCA4igAwIBAgIQTfpKgAsLZJhp2V4xUriMADANBgkqhkiG9w0BAQ0FADBp +MQswCQYDVQQGEwJVUzEUMBIGA1UECgwLR29vZ2xlIEluYy4xFzAVBgNVBAsMDkFu +ZHJvaWQgVGhpbmdzMSswKQYDVQQDDCJBbmRyb2lkIFRoaW5ncyBBdHRlc3RhdGlv +biBSb290IENBMCAXDTE3MDYyMTIwMjQzN1oYDzIwNTcwNjExMjAyNDM3WjBpMQsw +CQYDVQQGEwJVUzEUMBIGA1UECgwLR29vZ2xlIEluYy4xFzAVBgNVBAsMDkFuZHJv +aWQgVGhpbmdzMSswKQYDVQQDDCJBbmRyb2lkIFRoaW5ncyBBdHRlc3RhdGlvbiBS +b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuO82oerGivb9 +G9bWyM8Pg0y6SOnAC8/8b92dp1v4Npnc+QpjPRUKgn8lzjQ9Jo6IGY3OShRBiQYl +bbZYkfJnC5HtqbOETdPLZclErVE/G6Oda1IeZWvQVMjNImEYOLL5ct2RxiPttd8v +SLyOSNFPf5/SeFqX/La0NcmXMOvPSrTW3qO34brnC+ih7mlpJFLz6Up93N3Umxsl +IElz2wCG72t6k3+caWLyIPVgIPmsQrfTeBK/hN5dAJgAN65BsTevLHRP9J610wj3 +RagSIK1NdTuJRnr5ZyTQrwE2nA8H3IJ7/eo6IlGhXPwLKDhbdxYygPxdlCq6Rl96 +aVLjfpqDPtJ9ow+QKZuEDbYJ4z4olNXC6O5G7vqnCuULA/2E7y7DZObjzXOrdx2z +9YKd8BrIDMTN/5mmw2us8tywiaQhbl8vOtjU+A+iBBnkj/wt9TYyLKopdrDlo5mz +wy5l750HOkVZXC3VkeECnp+9duSHdS4qeUf/W1j9nPM7kY0HFLPUVX9AFVp2JXnC +iKZC32GQAVsDc1iyAZWAVTqA7E0fBHhk9jUnA0W9b5Lq06oW95ngNR1MIFY871i8 +aLHCBpIix8DuMe8NB9spCIP6WCQqGiWQQpzbeuBPtoi424xwZTO4oectTd77bs9V +Rvunn49fz308KnoWjk/by1N7gWyTb38CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMDQ1I0RKwFCI+Fy9uIIJ/HrXuqu +MA0GCSqGSIb3DQEBDQUAA4ICAQB09qkyEpEDocdN5pPeXqtjj9d0AXREUGH2LhnC +z9KZcUFR+JskwEMHCaOENOmKI3zWRmxT7d8cVywwGk+ExE7EBQoeHlh3Yo44M8aj +ZL7RHCvHRYsePhAJkYpJ02IMR60TV+1jhMqE8+BnqFivS7kft4t295EyrnLRZE3b +Nfc0t011j02RwUrioR57mdvS9EZBRnMQkobhn+jWt9O+V3mtplW+1A2n4ec6uni1 +2MMgAWHuO1sKVYd5Sp4JMUpNnfmQAMnNiOMF6VxkpaoF1lZWo4TrLxuDKJG3O8h1 +fByjCpNVY8kOvvYEadbldzh6Agy/3ppb9yfG7X7FtHr1ghNjuNT6w5VgvbRtoRja +/ZSKuJMaKm5emMWNkls/cwVSPJIvTOzPTeYK1BKSyAL2LDJ93HI7x8h79/Q7gKRi +kL8qT7GW2FqpWTK0253sJHqCJJP4A5Rxtf2+Afwqadfc6Ga4jJHb7rPXngz4j1ZB +gl5yjXgWF9wHGxqrjKWe2EA3d47BC4HG3Rf5L56KQiRPhTqTk5vtZwtwLRLFDLt7 +Hdff13O1oLhn+2z9xkASUL3rFE/qWajZP7fk3CvzcuXwKDTZomIC4nNaglx4nLdj +lHhOq+6ON8MZC46sLStD+D4a9A1HOoihJgI/yGGkwdrp4KQIveRkEBO/x9v3NNBE +bMwG9w== +-----END CERTIFICATE----- diff --git a/tests/AttestationVerificationTest/assets/test_root_certs.pem b/tests/AttestationVerificationTest/assets/test_root_certs.pem new file mode 100644 index 000000000000..c51851fe3da5 --- /dev/null +++ b/tests/AttestationVerificationTest/assets/test_root_certs.pem @@ -0,0 +1,61 @@ +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIJAOj6GWMU0voYMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV +BAUTEGY5MjAwOWU4NTNiNmIwNDUwHhcNMTYwNTI2MTYyODUyWhcNMjYwNTI0MTYy +ODUyWjAbMRkwFwYDVQQFExBmOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHsK7Qui8xUFmOr75gvMsd/dTEDDJdS +Sxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfdnJLmN0pTy/4lj4/7 +tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL/ggj +nar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGq +C4FSYa04T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQ +oVJYnFPlXTcHYvASLu+RhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+O +JtvsBslHZvPBKCOdT0MS+tgSOIfga+z1Z1g7+DVagf7quvmag8jfPioyKvxnK/Eg +sTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgpZrt3i5MIlCaY504LzSRi +igHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6tUXHI/+M +RPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9E +aDK8Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5Um +AGMCAwEAAaOBpjCBozAdBgNVHQ4EFgQUNmHhAHyIBQlRi0RsR/8aTMnqTxIwHwYD +VR0jBBgwFoAUNmHhAHyIBQlRi0RsR/8aTMnqTxIwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAYYwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cHM6Ly9hbmRyb2lk +Lmdvb2dsZWFwaXMuY29tL2F0dGVzdGF0aW9uL2NybC8wDQYJKoZIhvcNAQELBQAD +ggIBACDIw41L3KlXG0aMiS//cqrG+EShHUGo8HNsw30W1kJtjn6UBwRM6jnmiwfB +Pb8VA91chb2vssAtX2zbTvqBJ9+LBPGCdw/E53Rbf86qhxKaiAHOjpvAy5Y3m00m +qC0w/Zwvju1twb4vhLaJ5NkUJYsUS7rmJKHHBnETLi8GFqiEsqTWpG/6ibYCv7rY +DBJDcR9W62BW9jfIoBQcxUCUJouMPH25lLNcDc1ssqvC2v7iUgI9LeoM1sNovqPm +QUiG9rHli1vXxzCyaMTjwftkJLkf6724DFhuKug2jITV0QkXvaJWF4nUaHOTNA4u +JU9WDvZLI1j83A+/xnAJUucIv/zGJ1AMH2boHqF8CY16LpsYgBt6tKxxWH00XcyD +CdW2KlBCeqbQPcsFmWyWugxdcekhYsAWyoSf818NUsZdBWBaR/OukXrNLfkQ79Iy +ZohZbvabO/X+MVT3rriAoKc8oE2Uws6DF+60PV7/WIPjNvXySdqspImSN78mflxD +qwLqRBYkA3I75qppLGG9rp7UCdRjxMl8ZDBld+7yvHVgt1cVzJx9xnyGCC23Uaic +MDSXYrB4I4WHXPGjxhZuCuPBLTdOLU8YRvMYdEvYebWHMpvwGCF6bAx3JBpIeOQ1 +wDB5y0USicV3YgYGmi+NZfhA4URSh77Yd6uuJOJENRaNVTzk +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFHDCCAwSgAwIBAgIJANUP8luj8tazMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV +BAUTEGY5MjAwOWU4NTNiNmIwNDUwHhcNMTkxMTIyMjAzNzU4WhcNMzQxMTE4MjAz +NzU4WjAbMRkwFwYDVQQFExBmOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHsK7Qui8xUFmOr75gvMsd/dTEDDJdS +Sxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfdnJLmN0pTy/4lj4/7 +tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL/ggj +nar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGq +C4FSYa04T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQ +oVJYnFPlXTcHYvASLu+RhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+O +JtvsBslHZvPBKCOdT0MS+tgSOIfga+z1Z1g7+DVagf7quvmag8jfPioyKvxnK/Eg +sTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgpZrt3i5MIlCaY504LzSRi +igHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6tUXHI/+M +RPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9E +aDK8Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5Um +AGMCAwEAAaNjMGEwHQYDVR0OBBYEFDZh4QB8iAUJUYtEbEf/GkzJ6k8SMB8GA1Ud +IwQYMBaAFDZh4QB8iAUJUYtEbEf/GkzJ6k8SMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgIEMA0GCSqGSIb3DQEBCwUAA4ICAQBOMaBc8oumXb2voc7XCWnu +XKhBBK3e2KMGz39t7lA3XXRe2ZLLAkLM5y3J7tURkf5a1SutfdOyXAmeE6SRo83U +h6WszodmMkxK5GM4JGrnt4pBisu5igXEydaW7qq2CdC6DOGjG+mEkN8/TA6p3cno +L/sPyz6evdjLlSeJ8rFBH6xWyIZCbrcpYEJzXaUOEaxxXxgYz5/cTiVKN2M1G2ok +QBUIYSY6bjEL4aUN5cfo7ogP3UvliEo3Eo0YgwuzR2v0KR6C1cZqZJSTnghIC/vA +D32KdNQ+c3N+vl2OTsUVMC1GiWkngNx1OO1+kXW+YTnnTUOtOIswUP/Vqd5SYgAI +mMAfY8U9/iIgkQj6T2W6FsScy94IN9fFhE1UtzmLoBIuUFsVXJMTz+Jucth+IqoW +Fua9v1R93/k98p41pjtFX+H8DslVgfP097vju4KDlqN64xV1grw3ZLl4CiOe/A91 +oeLm2UHOq6wn3esB4r2EIQKb6jTVGu5sYCcdWpXr0AUVqcABPdgL+H7qJguBw09o +jm6xNIrw2OocrDKsudk/okr/AwqEyPKw9WnMlQgLIKw1rODG2NvU9oR3GVGdMkUB +ZutL8VuFkERQGt6vQ2OCw0sV47VMkuYbacK/xyZFiRcrPJPb41zgbQj9XAEyLKCH +ex0SdDrx+tWUDqG8At2JHA== +-----END CERTIFICATE----- diff --git a/tests/AttestationVerificationTest/assets/test_virtual_device_attestation_certs.pem b/tests/AttestationVerificationTest/assets/test_virtual_device_attestation_certs.pem new file mode 100644 index 000000000000..282771000bf7 --- /dev/null +++ b/tests/AttestationVerificationTest/assets/test_virtual_device_attestation_certs.pem @@ -0,0 +1,50 @@ +-----BEGIN CERTIFICATE----- +MIIC7DCCApGgAwIBAgIBATAKBggqhkjOPQQDAjCBiDELMAkGA1UEBhMCVVMxEzAR +BgNVBAgMCkNhbGlmb3JuaWExFTATBgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UE +CwwHQW5kcm9pZDE7MDkGA1UEAwwyQW5kcm9pZCBLZXlzdG9yZSBTb2Z0d2FyZSBB +dHRlc3RhdGlvbiBJbnRlcm1lZGlhdGUwHhcNNzAwMTAxMDAwMDAwWhcNNjkxMjMx +MjM1OTU5WjAfMR0wGwYDVQQDDBRBbmRyb2lkIEtleXN0b3JlIEtleTBZMBMGByqG +SM49AgEGCCqGSM49AwEHA0IABEYtCH28qu+St0F0TixVsQz0L/Y7DcRHgYAU98E6 +edwOpACFmmseYxMjvmZv/4jURSG2/Z0J1s3A/qFzIY96/tyjggFSMIIBTjALBgNV +HQ8EBAMCB4AwggEcBgorBgEEAdZ5AgERBIIBDDCCAQgCAQQKAQACASkKAQAECXBs +YXllcjQ1NgQAMIHqoQgxBgIBAgIBA6IDAgEDowQCAgEApQgxBgIBBAIBBqoDAgEB +v4N3AgUAv4U9CAIGAX8DoY9Qv4U+AwIBAL+FQEwwSgQgAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAABAQAKAQIEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAv4VBBQIDAa2wv4VCBQIDAxUbv4VFRwRFMEMxHTAbBBZjb20uZ29v +Z2xlLmF0dGVzdGF0aW9uAgEBMSIEIDqslV0SVHQBmP11cfMv7kT4nm6pchC7dRKa +iM9vYebVMAAwHwYDVR0jBBgwFoAUP/ys1hqxOp6BILjVJRzFZbsekakwCgYIKoZI +zj0EAwIDSQAwRgIhAMzs7gWWBIITpeLeEEx9B8ihdhkFqpMGlsYLRO01ZIOeAiEA +uKs9xfK3fIOpVAhDmsrp+zE8KUwyvqCU/IS13tXz7Ng= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICeDCCAh6gAwIBAgICEAEwCgYIKoZIzj0EAwIwgZgxCzAJBgNVBAYTAlVTMRMw +EQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRUwEwYD +VQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQxMzAxBgNVBAMMKkFu +ZHJvaWQgS2V5c3RvcmUgU29mdHdhcmUgQXR0ZXN0YXRpb24gUm9vdDAeFw0xNjAx +MTEwMDQ2MDlaFw0yNjAxMDgwMDQ2MDlaMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE +CAwKQ2FsaWZvcm5pYTEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdB +bmRyb2lkMTswOQYDVQQDDDJBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVz +dGF0aW9uIEludGVybWVkaWF0ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOue +efhCY1msyyqRTImGzHCtkGaTgqlzJhP+rMv4ISdMIXSXSir+pblNf2bU4GUQZjW8 +U7ego6ZxWD7bPhGuEBSjZjBkMB0GA1UdDgQWBBQ//KzWGrE6noEguNUlHMVlux6R +qTAfBgNVHSMEGDAWgBTIrel3TEXDo88NFhDkeUM6IVowzzASBgNVHRMBAf8ECDAG +AQH/AgEAMA4GA1UdDwEB/wQEAwIChDAKBggqhkjOPQQDAgNIADBFAiBLipt77oK8 +wDOHri/AiZi03cONqycqRZ9pDMfDktQPjgIhAO7aAV229DLp1IQ7YkyUBO86fMy9 +Xvsiu+f+uXc/WT/7 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICizCCAjKgAwIBAgIJAKIFntEOQ1tXMAoGCCqGSM49BAMCMIGYMQswCQYDVQQG +EwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmll +dzEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMTMwMQYD +VQQDDCpBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVzdGF0aW9uIFJvb3Qw +HhcNMTYwMTExMDA0MzUwWhcNMzYwMTA2MDA0MzUwWjCBmDELMAkGA1UEBhMCVVMx +EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT +BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEzMDEGA1UEAwwq +QW5kcm9pZCBLZXlzdG9yZSBTb2Z0d2FyZSBBdHRlc3RhdGlvbiBSb290MFkwEwYH +KoZIzj0CAQYIKoZIzj0DAQcDQgAE7l1ex+HA220Dpn7mthvsTWpdamguD/9/SQ59 +dx9EIm29sa/6FsvHrcV30lacqrewLVQBXT5DKyqO107sSHVBpKNjMGEwHQYDVR0O +BBYEFMit6XdMRcOjzw0WEOR5QzohWjDPMB8GA1UdIwQYMBaAFMit6XdMRcOjzw0W +EOR5QzohWjDPMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKEMAoGCCqG +SM49BAMCA0cAMEQCIDUho++LNEYenNVg8x1YiSBq3KNlQfYNns6KGYxmSGB7AiBN +C/NR2TB8fVvaNTQdqEcbY6WFZTytTySn502vQX3xvw== +-----END CERTIFICATE----- diff --git a/tests/AttestationVerificationTest/src/android/security/attestationverification/PeerDeviceSystemAttestationVerificationTest.kt b/tests/AttestationVerificationTest/src/android/security/attestationverification/PeerDeviceSystemAttestationVerificationTest.kt new file mode 100644 index 000000000000..32c2230e4880 --- /dev/null +++ b/tests/AttestationVerificationTest/src/android/security/attestationverification/PeerDeviceSystemAttestationVerificationTest.kt @@ -0,0 +1,161 @@ +package android.security.attestationverification + +import android.app.Activity +import android.os.Bundle +import android.security.attestationverification.AttestationVerificationManager.PARAM_CHALLENGE +import android.security.attestationverification.AttestationVerificationManager.PARAM_PUBLIC_KEY +import android.security.attestationverification.AttestationVerificationManager.PROFILE_PEER_DEVICE +import android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE +import android.security.attestationverification.AttestationVerificationManager.TYPE_CHALLENGE +import android.security.attestationverification.AttestationVerificationManager.TYPE_PUBLIC_KEY +import android.security.attestationverification.AttestationVerificationManager.TYPE_UNKNOWN +import androidx.test.ext.junit.rules.ActivityScenarioRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import java.io.ByteArrayOutputStream +import java.security.cert.CertificateFactory +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit + +/** Test for system-defined attestation verifiers. */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class PeerDeviceSystemAttestationVerificationTest { + + @get:Rule + val rule = ActivityScenarioRule(TestActivity::class.java) + + private val certifcateFactory = CertificateFactory.getInstance("X.509") + private lateinit var activity: Activity + private lateinit var avm: AttestationVerificationManager + private lateinit var invalidAttestationByteArray: ByteArray + + @Before + fun setup() { + rule.getScenario().onActivity { + avm = it.getSystemService(AttestationVerificationManager::class.java) + activity = it + } + invalidAttestationByteArray = TEST_ATTESTATION_CERT_FILENAME.fromPEMFileToByteArray() + } + + @Test + fun verifyAttestation_returnsFailureWrongBindingType() { + val future = CompletableFuture<Int>() + val profile = AttestationProfile(PROFILE_PEER_DEVICE) + avm.verifyAttestation(profile, TYPE_UNKNOWN, Bundle(), + invalidAttestationByteArray, activity.mainExecutor) { result, _ -> + future.complete(result) + } + + assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE) + } + + @Test + fun verifyAttestation_returnsFailureEmptyRequirements() { + val future = CompletableFuture<Int>() + val profile = AttestationProfile(PROFILE_PEER_DEVICE) + avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, Bundle(), + invalidAttestationByteArray, activity.mainExecutor) { result, _ -> + future.complete(result) + } + + assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE) + } + + @Test + fun verifyAttestation_returnsFailureMismatchBindingType() { + val future = CompletableFuture<Int>() + val profile = AttestationProfile(PROFILE_PEER_DEVICE) + val publicKeyRequirements = Bundle() + publicKeyRequirements.putByteArray(PARAM_PUBLIC_KEY, "publicKeyStr".encodeToByteArray()) + avm.verifyAttestation(profile, TYPE_CHALLENGE, publicKeyRequirements, + invalidAttestationByteArray, activity.mainExecutor) { result, _ -> + future.complete(result) + } + + assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE) + + val future2 = CompletableFuture<Int>() + val challengeRequirements = Bundle() + challengeRequirements.putByteArray(PARAM_CHALLENGE, "challengeStr".encodeToByteArray()) + avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, challengeRequirements, + invalidAttestationByteArray, activity.mainExecutor) { result, _ -> + future2.complete(result) + } + + assertThat(future2.getSoon()).isEqualTo(RESULT_FAILURE) + } + + @Test + fun verifyAttestation_returnsFailureWrongResourceKey() { + val future = CompletableFuture<Int>() + val profile = AttestationProfile(PROFILE_PEER_DEVICE) + val wrongKeyRequirements = Bundle() + wrongKeyRequirements.putByteArray("wrongReqKey", "publicKeyStr".encodeToByteArray()) + avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, wrongKeyRequirements, + invalidAttestationByteArray, activity.mainExecutor) { result, _ -> + future.complete(result) + } + + assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE) + } + + @Test + fun verifyAttestation_returnsFailureEmptyAttestation() { + val future = CompletableFuture<Int>() + val profile = AttestationProfile(PROFILE_PEER_DEVICE) + val requirements = Bundle() + requirements.putByteArray(PARAM_PUBLIC_KEY, "publicKeyStr".encodeToByteArray()) + avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, requirements, ByteArray(0), + activity.mainExecutor) { result, _ -> + future.complete(result) + } + + assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE) + } + + @Test + fun verifyAttestation_returnsFailureTrustAnchorMismatch() { + val future = CompletableFuture<Int>() + val profile = AttestationProfile(PROFILE_PEER_DEVICE) + val challengeRequirements = Bundle() + challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray()) + avm.verifyAttestation(profile, TYPE_CHALLENGE, challengeRequirements, + invalidAttestationByteArray, activity.mainExecutor) { result, _ -> + future.complete(result) + } + assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE) + } + + private fun <T> CompletableFuture<T>.getSoon(): T { + return this.get(1, TimeUnit.SECONDS) + } + + private fun String.fromPEMFileToByteArray(): ByteArray { + val certs = certifcateFactory.generateCertificates( + InstrumentationRegistry.getInstrumentation().getContext().getResources().getAssets() + .open(this)) + val bos = ByteArrayOutputStream() + certs.forEach { + bos.write(it.encoded) + } + return bos.toByteArray() + } + + class TestActivity : Activity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } + } + + companion object { + private const val TEST_ATTESTATION_CERT_FILENAME = "test_attestation_wrong_root_certs.pem" + } +} diff --git a/tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt b/tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt index 62902929fcd5..169effaa45ca 100644 --- a/tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt +++ b/tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt @@ -12,8 +12,8 @@ import org.junit.Test import org.junit.runner.RunWith import com.google.common.truth.Truth.assertThat import android.security.attestationverification.AttestationVerificationManager.PARAM_CHALLENGE -import android.security.attestationverification.AttestationVerificationManager.PROFILE_PEER_DEVICE import android.security.attestationverification.AttestationVerificationManager.PROFILE_SELF_TRUSTED +import android.security.attestationverification.AttestationVerificationManager.PROFILE_UNKNOWN import android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE import android.security.attestationverification.AttestationVerificationManager.RESULT_SUCCESS import android.security.attestationverification.AttestationVerificationManager.RESULT_UNKNOWN @@ -52,7 +52,7 @@ class SystemAttestationVerificationTest { @Test fun verifyAttestation_returnsUnknown() { val future = CompletableFuture<Int>() - val profile = AttestationProfile(PROFILE_PEER_DEVICE) + val profile = AttestationProfile(PROFILE_UNKNOWN) avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, Bundle(), ByteArray(0), activity.mainExecutor) { result, _ -> future.complete(result) @@ -137,7 +137,7 @@ class SystemAttestationVerificationTest { @Test fun verifyToken_returnsUnknown() { val future = CompletableFuture<Int>() - val profile = AttestationProfile(PROFILE_PEER_DEVICE) + val profile = AttestationProfile(PROFILE_SELF_TRUSTED) avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, Bundle(), ByteArray(0), activity.mainExecutor) { _, token -> val result = avm.verifyToken(profile, TYPE_PUBLIC_KEY, Bundle(), token, null) @@ -150,7 +150,7 @@ class SystemAttestationVerificationTest { @Test fun verifyToken_tooBigMaxAgeThrows() { val future = CompletableFuture<VerificationToken>() - val profile = AttestationProfile(PROFILE_PEER_DEVICE) + val profile = AttestationProfile(PROFILE_SELF_TRUSTED) avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, Bundle(), ByteArray(0), activity.mainExecutor) { _, token -> future.complete(token) diff --git a/tests/AttestationVerificationTest/src/com/android/server/security/AndroidKeystoreAttestationVerificationAttributesTest.java b/tests/AttestationVerificationTest/src/com/android/server/security/AndroidKeystoreAttestationVerificationAttributesTest.java new file mode 100644 index 000000000000..0d15fe72920a --- /dev/null +++ b/tests/AttestationVerificationTest/src/com/android/server/security/AndroidKeystoreAttestationVerificationAttributesTest.java @@ -0,0 +1,297 @@ +/* + * 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.security; + +import static com.google.common.truth.Truth.assertThat; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + +import org.hamcrest.CoreMatchers; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; + +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** Test for data class holding parsed X509Certificate attestation attributes. */ +@RunWith(AndroidJUnit4.class) +public class AndroidKeystoreAttestationVerificationAttributesTest { + @Rule public ExpectedException mException = ExpectedException.none(); + private static final String TEST_PHYSCIAL_DEVICE_CERTS = + "test_attestation_wrong_root_certs.pem"; + private static final String TEST_PHYSICAL_DEVICE_CERTS_2 = + "test_attestation_with_root_certs.pem"; + private static final String TEST_VIRTUAL_DEVICE_CERTS = + "test_virtual_device_attestation_certs.pem"; + private static final String TEST_CERT_NO_ATTESTATION_EXTENSION = + "test_no_attestation_ext_certs.pem"; + private static final String TEST_CERTS_NO_ATTESTATION_EXTENSION_2 = + "test_root_certs.pem"; + + + private CertificateFactory mFactory; + private AndroidKeystoreAttestationVerificationAttributes mPhysicalDeviceAttributes; + private AndroidKeystoreAttestationVerificationAttributes mPhysicalDeviceAttributes2; + private AndroidKeystoreAttestationVerificationAttributes mVirtualDeviceAttributes; + + @Before + public void setUp() throws Exception { + mFactory = CertificateFactory.getInstance("X.509"); + mPhysicalDeviceAttributes = + AndroidKeystoreAttestationVerificationAttributes.fromCertificate( + generateCertificate(TEST_PHYSCIAL_DEVICE_CERTS)); + mPhysicalDeviceAttributes2 = + AndroidKeystoreAttestationVerificationAttributes.fromCertificate( + generateCertificates(TEST_PHYSICAL_DEVICE_CERTS_2).get(0)); + mVirtualDeviceAttributes = + AndroidKeystoreAttestationVerificationAttributes.fromCertificate( + generateCertificates(TEST_VIRTUAL_DEVICE_CERTS).get(0)); + } + + @Test + public void parseCertificate_noAttestationExtension() throws Exception { + List<X509Certificate> certsNoAttestation = + generateCertificates(TEST_CERTS_NO_ATTESTATION_EXTENSION_2); + certsNoAttestation.add(generateCertificate(TEST_CERT_NO_ATTESTATION_EXTENSION)); + for (X509Certificate cert: certsNoAttestation) { + mException.expect(CertificateEncodingException.class); + mException.expectMessage( + CoreMatchers.containsString("No attestation extension found in certificate.")); + + AndroidKeystoreAttestationVerificationAttributes.fromCertificate(cert); + } + } + + @Test + public void parseCertificate_attestationLevel() { + assertThat(mPhysicalDeviceAttributes.getAttestationVersion()).isEqualTo(3); + assertThat(mPhysicalDeviceAttributes2.getAttestationVersion()).isEqualTo(3); + assertThat(mVirtualDeviceAttributes.getAttestationVersion()).isEqualTo(4); + } + + @Test + public void parseCertificate_attestationSecurityLevel() { + assertThat(mPhysicalDeviceAttributes.getAttestationSecurityLevel()).isEqualTo( + AndroidKeystoreAttestationVerificationAttributes.SecurityLevel.TRUSTED_ENVIRONMENT); + assertThat(mPhysicalDeviceAttributes2.getAttestationSecurityLevel()).isEqualTo( + AndroidKeystoreAttestationVerificationAttributes.SecurityLevel.TRUSTED_ENVIRONMENT); + assertThat(mVirtualDeviceAttributes.getAttestationSecurityLevel()).isEqualTo( + AndroidKeystoreAttestationVerificationAttributes.SecurityLevel.SOFTWARE); + } + + @Test + public void parseCertificate_isAttestationHardwareBacked() { + assertThat(mPhysicalDeviceAttributes.isAttestationHardwareBacked()).isTrue(); + assertThat(mPhysicalDeviceAttributes2.isAttestationHardwareBacked()).isTrue(); + assertThat(mVirtualDeviceAttributes.isAttestationHardwareBacked()).isFalse(); + } + + @Test + public void parseCertificate_keymasterLevel() { + assertThat(mPhysicalDeviceAttributes.getKeymasterVersion()).isEqualTo(4); + assertThat(mPhysicalDeviceAttributes2.getKeymasterVersion()).isEqualTo(4); + assertThat(mVirtualDeviceAttributes.getKeymasterVersion()).isEqualTo(41); + } + + @Test + public void parseCertificate_keymasterSecurityLevel() { + assertThat(mPhysicalDeviceAttributes.getKeymasterSecurityLevel()).isEqualTo( + AndroidKeystoreAttestationVerificationAttributes.SecurityLevel.TRUSTED_ENVIRONMENT); + assertThat(mPhysicalDeviceAttributes2.getKeymasterSecurityLevel()).isEqualTo( + AndroidKeystoreAttestationVerificationAttributes.SecurityLevel.TRUSTED_ENVIRONMENT); + assertThat(mVirtualDeviceAttributes.getKeymasterSecurityLevel()).isEqualTo( + AndroidKeystoreAttestationVerificationAttributes.SecurityLevel.SOFTWARE); + } + + @Test + public void parseCertificate_isKeymasterHardwareBacked() { + assertThat(mPhysicalDeviceAttributes.isKeymasterHardwareBacked()).isTrue(); + assertThat(mPhysicalDeviceAttributes2.isKeymasterHardwareBacked()).isTrue(); + assertThat(mVirtualDeviceAttributes.isKeymasterHardwareBacked()).isFalse(); + } + + @Test + public void parseCertificate_attestationChallenge() { + assertThat(mPhysicalDeviceAttributes.getAttestationChallenge().toByteArray()).isEqualTo( + "abc".getBytes(UTF_8)); + assertThat(mPhysicalDeviceAttributes2.getAttestationChallenge().toByteArray()).isEqualTo( + "player456".getBytes(UTF_8)); + assertThat(mVirtualDeviceAttributes.getAttestationChallenge().toByteArray()).isEqualTo( + "player456".getBytes(UTF_8)); + } + + @Test + public void parseCertificate_verifiedBootState() { + assertThat(mPhysicalDeviceAttributes.getVerifiedBootState()).isEqualTo( + AndroidKeystoreAttestationVerificationAttributes.VerifiedBootState.UNVERIFIED); + assertThat(mPhysicalDeviceAttributes2.getVerifiedBootState()).isEqualTo( + AndroidKeystoreAttestationVerificationAttributes.VerifiedBootState.VERIFIED); + assertThat(mVirtualDeviceAttributes.getVerifiedBootState()).isNull(); + } + + @Test + public void parseCertificate_keyBootPatchLevel() { + assertThat(mPhysicalDeviceAttributes.getKeyBootPatchLevel()).isEqualTo(201907); + assertThat(mPhysicalDeviceAttributes2.getKeyBootPatchLevel()).isEqualTo(20220105); + } + + @Test + public void parseCertificate_keyBootPatchLevelNotSetException() { + mException.expect(IllegalStateException.class); + mException.expectMessage( + CoreMatchers.containsString("KeyBootPatchLevel is not set.")); + + mVirtualDeviceAttributes.getKeyBootPatchLevel(); + } + + @Test + public void parseCertificate_keyOsPatchLevel() { + assertThat(mPhysicalDeviceAttributes.getKeyOsPatchLevel()).isEqualTo(201907); + assertThat(mPhysicalDeviceAttributes2.getKeyOsPatchLevel()).isEqualTo(202201); + } + + @Test + public void parseCertificate_keyOsPatchLevelNotSetException() { + mException.expect(IllegalStateException.class); + mException.expectMessage( + CoreMatchers.containsString("KeyOsPatchLevel is not set.")); + + mVirtualDeviceAttributes.getKeyOsPatchLevel(); + } + + @Test + public void parseCertificate_keyVendorPatchLevel() { + assertThat(mPhysicalDeviceAttributes.getKeyVendorPatchLevel()).isEqualTo(201907); + assertThat(mPhysicalDeviceAttributes2.getKeyVendorPatchLevel()).isEqualTo(20220105); + } + + @Test + public void parseCertificate_keyVendorPatchLevelNotSetException() { + mException.expect(IllegalStateException.class); + mException.expectMessage( + CoreMatchers.containsString("KeyVendorPatchLevel is not set.")); + + mVirtualDeviceAttributes.getKeyVendorPatchLevel(); + } + + @Test + public void parseCertificate_keyAuthenticatorType() { + assertThat(mPhysicalDeviceAttributes.getKeyAuthenticatorType()).isEqualTo(0); + assertThat(mPhysicalDeviceAttributes2.getKeyAuthenticatorType()).isEqualTo(0); + } + + @Test + public void parseCertificate_keyOsVersion() { + assertThat(mPhysicalDeviceAttributes.getKeyOsVersion()).isEqualTo(0); + assertThat(mPhysicalDeviceAttributes2.getKeyOsVersion()).isEqualTo(120000); + } + + @Test + public void parseCertificate_keyOsVersionNotSetException() { + mException.expect(IllegalStateException.class); + mException.expectMessage( + CoreMatchers.containsString("KeyOsVersion is not set.")); + + mVirtualDeviceAttributes.getKeyOsVersion(); + } + + @Test + public void parseCertificate_verifiedBootHash() { + assertThat(mPhysicalDeviceAttributes.getVerifiedBootHash()).isNotEmpty(); + assertThat(mPhysicalDeviceAttributes2.getVerifiedBootHash()).isNotEmpty(); + } + + @Test + public void parseCertificate_verifiedBootKey() { + assertThat(mPhysicalDeviceAttributes.getVerifiedBootKey()).isNotEmpty(); + assertThat(mPhysicalDeviceAttributes2.getVerifiedBootKey()).isNotEmpty(); + } + + @Test + public void parseCertificate_isVerifiedBootLocked() { + assertThat(mPhysicalDeviceAttributes.isVerifiedBootLocked()).isFalse(); + assertThat(mPhysicalDeviceAttributes2.isVerifiedBootLocked()).isTrue(); + } + + @Test + public void parseCertificate_isVerifiedBootLockedNotSetException() { + mException.expect(IllegalStateException.class); + mException.expectMessage( + CoreMatchers.containsString("VerifiedBootLocked is not set.")); + + mVirtualDeviceAttributes.isVerifiedBootLocked(); + } + + @Test + public void parseCertificate_applicationPackageNameVersion() { + assertThat(mPhysicalDeviceAttributes.getApplicationPackageNameVersion()).isNotEmpty(); + } + + @Test + public void parseCertificate_applicationCertificateDigests() { + assertThat(mPhysicalDeviceAttributes.getApplicationCertificateDigests()).isNotEmpty(); + } + + @Test + public void parseCertificate_valuesNotSet() { + assertThat(mPhysicalDeviceAttributes.getDeviceBrand()).isNull(); + assertThat(mPhysicalDeviceAttributes.getDeviceName()).isNull(); + assertThat(mPhysicalDeviceAttributes.getDeviceProductName()).isNull(); + assertThat(mPhysicalDeviceAttributes.isKeyAllowedForAllApplications()).isFalse(); + assertThat(mPhysicalDeviceAttributes2.getDeviceBrand()).isNull(); + assertThat(mPhysicalDeviceAttributes2.getDeviceName()).isNull(); + assertThat(mPhysicalDeviceAttributes2.getDeviceProductName()).isNull(); + assertThat(mPhysicalDeviceAttributes2.isKeyAllowedForAllApplications()).isFalse(); + } + + @Test + public void parseCertificate_keyRequiresUnlockedDeviceNotSetException() { + mException.expect(IllegalStateException.class); + mException.expectMessage( + CoreMatchers.containsString("KeyRequiresUnlockedDevice is not set.")); + + mPhysicalDeviceAttributes.isKeyRequiresUnlockedDevice(); + } + + private X509Certificate generateCertificate(String certificateString) + throws Exception { + return generateCertificates(certificateString).get(0); + } + + private List<X509Certificate> generateCertificates(String certificateString) + throws Exception { + Collection<? extends Certificate> certificates = mFactory.generateCertificates( + InstrumentationRegistry.getInstrumentation().getContext().getResources().getAssets() + .open(certificateString)); + + ArrayList<X509Certificate> x509Certs = new ArrayList<>(); + for (Certificate cert : certificates) { + x509Certs.add((X509Certificate) cert); + } + return x509Certs; + } +} diff --git a/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt b/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt new file mode 100644 index 000000000000..45f2e5c6fdf7 --- /dev/null +++ b/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt @@ -0,0 +1,175 @@ +package com.android.server.security + +import android.app.Activity +import android.content.Context +import android.os.Bundle +import android.security.attestationverification.AttestationVerificationManager.PARAM_CHALLENGE +import android.security.attestationverification.AttestationVerificationManager.PARAM_PUBLIC_KEY +import android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE +import android.security.attestationverification.AttestationVerificationManager.RESULT_SUCCESS +import android.security.attestationverification.AttestationVerificationManager.TYPE_CHALLENGE +import android.security.attestationverification.AttestationVerificationManager.TYPE_PUBLIC_KEY +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import java.io.ByteArrayOutputStream +import java.security.cert.Certificate +import java.security.cert.CertificateFactory +import java.security.cert.TrustAnchor +import java.security.cert.X509Certificate +import java.time.LocalDate + +/** Test for Peer Device attestation verifier. */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class AttestationVerificationPeerDeviceVerifierTest { + private val certificateFactory = CertificateFactory.getInstance("X.509") + @Mock private lateinit var context: Context + private lateinit var trustAnchors: HashSet<TrustAnchor> + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + + val rootCerts = TEST_ROOT_CERT_FILENAME.fromPEMFileToCerts() + trustAnchors = HashSet<TrustAnchor>() + rootCerts.forEach { + trustAnchors.add(TrustAnchor(it as X509Certificate, null)) + } + } + + @Test + fun verifyAttestation_returnsSuccessTypeChallenge() { + val verifier = AttestationVerificationPeerDeviceVerifier( + context, trustAnchors, false, LocalDate.of(2022, 2, 1), + LocalDate.of(2021, 8, 1)) + val challengeRequirements = Bundle() + challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray()) + + val result = verifier.verifyAttestation(TYPE_CHALLENGE, challengeRequirements, + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + assertThat(result).isEqualTo(RESULT_SUCCESS) + } + + @Test + fun verifyAttestation_returnsSuccessLocalPatchOlderThanOneYear() { + val verifier = AttestationVerificationPeerDeviceVerifier( + context, trustAnchors, false, LocalDate.of(2022, 2, 1), + LocalDate.of(2021, 1, 1)) + val challengeRequirements = Bundle() + challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray()) + + val result = verifier.verifyAttestation(TYPE_CHALLENGE, challengeRequirements, + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + assertThat(result).isEqualTo(RESULT_SUCCESS) + } + + @Test + fun verifyAttestation_returnsSuccessTypePublicKey() { + val verifier = AttestationVerificationPeerDeviceVerifier( + context, trustAnchors, false, LocalDate.of(2022, 2, 1), + LocalDate.of(2021, 8, 1)) + + val leafCert = + (TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToCerts() as List)[0] + as X509Certificate + val pkRequirements = Bundle() + pkRequirements.putByteArray(PARAM_PUBLIC_KEY, leafCert.publicKey.encoded) + + val result = verifier.verifyAttestation( + TYPE_PUBLIC_KEY, pkRequirements, + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + assertThat(result).isEqualTo(RESULT_SUCCESS) + } + + @Test + fun verifyAttestation_returnsFailurePatchDateNotWithinOneYearLocalPatch() { + val verifier = AttestationVerificationPeerDeviceVerifier( + context, trustAnchors, false, LocalDate.of(2023, 3, 1), + LocalDate.of(2023, 2, 1)) + val challengeRequirements = Bundle() + challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray()) + + val result = verifier.verifyAttestation(TYPE_CHALLENGE, challengeRequirements, + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + assertThat(result).isEqualTo(RESULT_FAILURE) + } + + @Test + fun verifyAttestation_returnsFailureTrustedAnchorEmpty() { + val verifier = AttestationVerificationPeerDeviceVerifier( + context, HashSet(), false, LocalDate.of(2022, 1, 1), + LocalDate.of(2022, 1, 1)) + val challengeRequirements = Bundle() + challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray()) + + val result = verifier.verifyAttestation(TYPE_CHALLENGE, challengeRequirements, + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + assertThat(result).isEqualTo(RESULT_FAILURE) + } + + @Test + fun verifyAttestation_returnsFailureTrustedAnchorMismatch() { + val badTrustAnchorsCerts = TEST_ATTESTATION_CERT_FILENAME.fromPEMFileToCerts() + val badTrustAnchors = HashSet<TrustAnchor>() + badTrustAnchorsCerts.forEach { + badTrustAnchors.add(TrustAnchor(it as X509Certificate, null)) + } + + val verifier = AttestationVerificationPeerDeviceVerifier( + context, badTrustAnchors, false, LocalDate.of(2022, 1, 1), + LocalDate.of(2022, 1, 1)) + val challengeRequirements = Bundle() + challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray()) + + val result = verifier.verifyAttestation(TYPE_CHALLENGE, challengeRequirements, + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + assertThat(result).isEqualTo(RESULT_FAILURE) + } + + fun verifyAttestation_returnsFailureChallenge() { + val verifier = AttestationVerificationPeerDeviceVerifier( + context, trustAnchors, false, LocalDate.of(2022, 1, 1), + LocalDate.of(2022, 1, 1)) + val challengeRequirements = Bundle() + challengeRequirements.putByteArray(PARAM_CHALLENGE, "wrong".encodeToByteArray()) + + val result = verifier.verifyAttestation(TYPE_CHALLENGE, challengeRequirements, + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + assertThat(result).isEqualTo(RESULT_FAILURE) + } + + private fun String.fromPEMFileToCerts(): Collection<Certificate> { + return certificateFactory.generateCertificates( + InstrumentationRegistry.getInstrumentation().getContext().getResources().getAssets() + .open(this)) + } + + private fun String.fromPEMFileToByteArray(): ByteArray { + val certs = this.fromPEMFileToCerts() + val bos = ByteArrayOutputStream() + certs.forEach { + bos.write(it.encoded) + } + return bos.toByteArray() + } + + class TestActivity : Activity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } + } + + companion object { + private const val TEST_ROOT_CERT_FILENAME = "test_root_certs.pem" + private const val TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME = + "test_attestation_with_root_certs.pem" + private const val TEST_ATTESTATION_CERT_FILENAME = "test_attestation_wrong_root_certs.pem" + } +} diff --git a/tests/SurfaceViewSyncTest/Android.bp b/tests/SurfaceViewSyncTest/Android.bp new file mode 100644 index 000000000000..1c6e380aad63 --- /dev/null +++ b/tests/SurfaceViewSyncTest/Android.bp @@ -0,0 +1,31 @@ +// +// 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 { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test { + name: "SurfaceViewSyncTest", + srcs: ["**/*.java"], + platform_apis: true, + certificate: "platform", +} diff --git a/tests/SurfaceViewSyncTest/AndroidManifest.xml b/tests/SurfaceViewSyncTest/AndroidManifest.xml new file mode 100644 index 000000000000..d085f8c168d3 --- /dev/null +++ b/tests/SurfaceViewSyncTest/AndroidManifest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.test"> + <application> + <activity android:name="SurfaceViewSyncActivity" + android:label="SurfaceView Sync Test" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/SurfaceViewSyncTest/OWNERS b/tests/SurfaceViewSyncTest/OWNERS new file mode 100644 index 000000000000..0862c05e0ee4 --- /dev/null +++ b/tests/SurfaceViewSyncTest/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/wm/OWNERS diff --git a/tests/SurfaceViewSyncTest/res/layout/activity_surfaceview_sync.xml b/tests/SurfaceViewSyncTest/res/layout/activity_surfaceview_sync.xml new file mode 100644 index 000000000000..4433b2148384 --- /dev/null +++ b/tests/SurfaceViewSyncTest/res/layout/activity_surfaceview_sync.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:background="@android:color/darker_gray"
+ tools:context="com.example.mysurfaceview.MainActivity">
+
+ <SurfaceView
+ android:id="@+id/surface_view"
+ android:layout_width="match_parent"
+ android:layout_height="600dp" />
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <Button
+ android:text="COLLAPSE SV"
+ android:id="@+id/expand_sv"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ <Switch
+ android:id="@+id/enable_sync_switch"
+ android:text="Enable Sync"
+ android:checked="true"
+ android:layout_alignParentEnd="true"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ </RelativeLayout>
+</LinearLayout>
\ No newline at end of file diff --git a/tests/SurfaceViewSyncTest/src/com/android/test/SurfaceViewSyncActivity.java b/tests/SurfaceViewSyncTest/src/com/android/test/SurfaceViewSyncActivity.java new file mode 100644 index 000000000000..06accec09686 --- /dev/null +++ b/tests/SurfaceViewSyncTest/src/com/android/test/SurfaceViewSyncActivity.java @@ -0,0 +1,191 @@ +/* + * 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.test; + +import android.annotation.NonNull; +import android.app.Activity; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.WindowMetrics; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.Switch; +import android.window.SurfaceSyncer; + +/** + * Test app that allows the user to resize the SurfaceView and have the new buffer sync with the + * main window. This tests that {@link SurfaceSyncer} is working correctly. + */ +public class SurfaceViewSyncActivity extends Activity implements SurfaceHolder.Callback { + private static final String TAG = "SurfaceViewSyncActivity"; + + private SurfaceView mSurfaceView; + private boolean mLastExpanded = true; + + private RenderingThread mRenderingThread; + + private final SurfaceSyncer mSurfaceSyncer = new SurfaceSyncer(); + + private Button mExpandButton; + private Switch mEnableSyncSwitch; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_surfaceview_sync); + mSurfaceView = findViewById(R.id.surface_view); + mSurfaceView.getHolder().addCallback(this); + + WindowManager windowManager = getWindowManager(); + WindowMetrics metrics = windowManager.getCurrentWindowMetrics(); + Rect bounds = metrics.getBounds(); + + LinearLayout container = findViewById(R.id.container); + mExpandButton = findViewById(R.id.expand_sv); + mEnableSyncSwitch = findViewById(R.id.enable_sync_switch); + mExpandButton.setOnClickListener(view -> updateSurfaceViewSize(bounds, container)); + + mRenderingThread = new RenderingThread(mSurfaceView.getHolder()); + } + + private void updateSurfaceViewSize(Rect bounds, View container) { + final float height; + if (mLastExpanded) { + height = bounds.height() / 2f; + mExpandButton.setText("EXPAND SV"); + } else { + height = bounds.height() / 1.5f; + mExpandButton.setText("COLLAPSE SV"); + } + mLastExpanded = !mLastExpanded; + + if (mEnableSyncSwitch.isChecked()) { + int syncId = mSurfaceSyncer.setupSync(() -> { }); + mSurfaceSyncer.addToSync(syncId, mSurfaceView, frameCallback -> + mRenderingThread.setFrameCallback(frameCallback)); + mSurfaceSyncer.addToSync(syncId, container); + mSurfaceSyncer.markSyncReady(syncId); + } else { + mRenderingThread.renderSlow(); + } + + ViewGroup.LayoutParams svParams = mSurfaceView.getLayoutParams(); + svParams.height = (int) height; + mSurfaceView.setLayoutParams(svParams); + } + + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + final Canvas canvas = holder.lockCanvas(); + canvas.drawARGB(255, 100, 100, 100); + holder.unlockCanvasAndPost(canvas); + mRenderingThread.startRendering(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + mRenderingThread.stopRendering(); + } + + private static class RenderingThread extends HandlerThread { + private final SurfaceHolder mSurfaceHolder; + private Handler mHandler; + private SurfaceSyncer.SurfaceViewFrameCallback mFrameCallback; + private boolean mRenderSlow; + + int mColorValue = 0; + int mColorDelta = 10; + + RenderingThread(SurfaceHolder holder) { + super("RenderingThread"); + mSurfaceHolder = holder; + } + + public void setFrameCallback(SurfaceSyncer.SurfaceViewFrameCallback frameCallback) { + if (mHandler != null) { + mHandler.post(() -> { + mFrameCallback = frameCallback; + mRenderSlow = true; + }); + } + } + + public void renderSlow() { + if (mHandler != null) { + mHandler.post(() -> mRenderSlow = true); + } + } + + private final Runnable mRunnable = new Runnable() { + @Override + public void run() { + if (mFrameCallback != null) { + mFrameCallback.onFrameStarted(); + } + + if (mRenderSlow) { + try { + // Long delay from start to finish to mimic slow draw + Thread.sleep(1000); + } catch (InterruptedException e) { + } + mRenderSlow = false; + } + + mColorValue += mColorDelta; + if (mColorValue > 245 || mColorValue < 10) { + mColorDelta *= -1; + } + + Canvas c = mSurfaceHolder.lockCanvas(); + c.drawRGB(255, mColorValue, 255 - mColorValue); + mSurfaceHolder.unlockCanvasAndPost(c); + + if (mFrameCallback != null) { + mFrameCallback.onFrameComplete(); + } + mFrameCallback = null; + + mHandler.postDelayed(this, 50); + } + }; + + public void startRendering() { + start(); + mHandler = new Handler(getLooper()); + mHandler.post(mRunnable); + } + + public void stopRendering() { + if (mHandler != null) { + mHandler.post(() -> mHandler.removeCallbacks(mRunnable)); + } + } + } +} |